1。概要
このコードラボでは、インタラクティブなウェブアプリケーションを作成するためのFirebaseの基本をいくつか学びます。いくつかのFirebase製品を使用して、イベントの出欠確認とゲストブックのチャットアプリを作成します。
あなたが学ぶこと
- FirebaseAuthenticationとFirebaseUIを使用してユーザーを認証します。
- CloudFirestoreを使用してデータを同期します。
- データベースを保護するためのFirebaseセキュリティルールを作成します。
必要なもの
- Chromeなどの選択したブラウザ。
- stackblitz.comへのアクセス(アカウントやサインインは必要ありません)。
- GmailアカウントのようなGoogleアカウント。 GitHubアカウントですでに使用しているメールアカウントをお勧めします。これにより、StackBlitzの高度な機能を使用できます。
- codelabのサンプルコード。コードを取得する方法については、次の手順を参照してください。
2.開始コードを取得します
このコードラボでは、いくつかのFirebaseワークフローが統合されたオンラインエディターであるStackBlitzを使用してアプリを作成します。 Stackblitzには、ソフトウェアのインストールや特別なStackBlitzアカウントは必要ありません。
StackBlitzを使用すると、プロジェクトを他のユーザーと共有できます。 StackBlitzプロジェクトのURLを持っている他の人は、あなたのコードを見てプロジェクトをフォークすることはできますが、StackBlitzプロジェクトを編集することはできません。
- 開始コードについては、次のURLにアクセスしてください: https ://stackblitz.com/edit/firebase-gtk-web-start
- StackBlitzページの上部で、[フォーク]をクリックします。
これで、開始コードのコピーが独自のStackBlitzプロジェクトとして作成されました。これには、一意の名前と一意のURLが含まれています。すべてのファイルと変更は、このStackBlitzプロジェクトに保存されます。
3.イベント情報を編集します
このコードラボの開始資料は、いくつかのスタイルシートやアプリのHTMLコンテナーなど、Webアプリの構造を提供します。このコードラボの後半で、これらのコンテナをFirebaseに接続します。
はじめに、StackBlitzインターフェースについてもう少し詳しく見ていきましょう。
- StackBlitzで、
index.html
ファイルを開きます。 -
event-details-container
とdescription-container
を見つけて、イベントの詳細を編集してみてください。
テキストを編集すると、StackBlitzの自動ページリロードで新しいイベントの詳細が表示されます。かっこいいですね
<!-- ... -->
<div id="app">
<img src="..." />
<section id="event-details-container">
<h1>Firebase Meetup</h1>
<p><i class="material-icons">calendar_today</i> October 30</p>
<p><i class="material-icons">location_city</i> San Francisco</p>
</section>
<hr>
<section id="firebaseui-auth-container"></section>
<section id="description-container">
<h2>What we'll be doing</h2>
<p>Join us for a day full of Firebase Workshops and Pizza!</p>
</section>
</div>
<!-- ... -->
アプリのプレビューは次のようになります。
アプリのプレビュー
4.Firebaseプロジェクトを作成して設定します
イベント情報を表示することはゲストにとっては素晴らしいことですが、イベントを表示するだけでは誰にとってもあまり役に立ちません。このアプリにいくつかの動的機能を追加しましょう。このためには、Firebaseをアプリに接続する必要があります。 Firebaseの使用を開始するには、Firebaseプロジェクトを作成して設定する必要があります。
Firebaseプロジェクトを作成する
- Firebaseにログインします。
- Firebaseコンソールで、[プロジェクトの追加](または[プロジェクトの作成])をクリックし、FirebaseプロジェクトにFirebase-Web-Codelabという名前を付けます。
- プロジェクト作成オプションをクリックします。プロンプトが表示されたら、Firebaseの利用規約に同意します。このアプリではアナリティクスを使用しないため、Googleアナリティクス画面で[有効にしない]をクリックします。
Firebaseプロジェクトの詳細については、 「Firebaseプロジェクトについて理解する」をご覧ください。
コンソールでFirebase製品を有効にして設定する
作成しているアプリは、ウェブアプリで利用できるいくつかのFirebase製品を使用しています。
- FirebaseAuthenticationとFirebaseUIにより、ユーザーはアプリに簡単にログインできます。
- 構造化データをクラウドに保存し、データが変更されたときに即座に通知を受け取るCloudFirestore。
- データベースを保護するためのFirebaseセキュリティルール。
これらの製品の一部は、特別な設定が必要であるか、Firebaseコンソールを使用して有効にする必要があります。
Firebase認証のメールログインを有効にする
ユーザーがWebアプリにサインインできるようにするには、このコードラボで電子メール/パスワードのサインイン方法を使用します。
- Firebaseコンソールの左側のパネルで、[ビルド]>[認証]をクリックします。次に、[開始]をクリックします。これで、認証ダッシュボードが表示され、サインアップしたユーザーを確認したり、サインインプロバイダーを構成したり、設定を管理したりできます。
- [サインイン方法]タブを選択します(または、ここをクリックしてタブに直接移動します)。
- プロバイダーオプションから[電子メール/パスワード]をクリックし、スイッチを[有効]に切り替えて、[保存]をクリックします。
CloudFirestoreをセットアップする
Webアプリは、 Cloud Firestoreを使用してチャットメッセージを保存し、新しいチャットメッセージを受信します。
CloudFirestoreを設定する方法は次のとおりです。
- Firebaseコンソールの左側のパネルで、[ビルド]>[ Firestoreデータベース]をクリックします。次に、[データベースの作成]をクリックします。
- [データベースの作成]をクリックします。
- [テストモードで開始]オプションを選択します。セキュリティルールに関する免責事項をお読みください。テストモードでは、開発中にデータベースに自由に書き込むことができます。 [次へ]をクリックします。
- データベースの場所を選択します(デフォルトを使用できます)。ただし、この場所は後で変更できないことに注意してください。
- [完了]をクリックします。
5.Firebaseを追加して設定します
Firebaseプロジェクトを作成し、一部のサービスを有効にしたので、Firebaseを使用するコードと、使用するFirebaseプロジェクトを指定する必要があります。
Firebaseライブラリを追加する
アプリでFirebaseを使用するには、Firebaseライブラリをアプリに追加する必要があります。 Firebaseのドキュメントで説明されているように、これを行うには複数の方法があります。たとえば、GoogleのCDNからライブラリを追加したり、npmを使用してローカルにインストールしてから、Browserifyを使用している場合はアプリにパッケージ化することができます。
StackBlitzは自動バンドルを提供するため、インポートステートメントを使用してFirebaseライブラリを追加できます。ライブラリのモジュラー(v9)バージョンを使用します。これは、「ツリーシェイク」と呼ばれるプロセスを通じてWebページの全体的なサイズを縮小するのに役立ちます。モジュラーSDKの詳細については、ドキュメントをご覧ください。
このアプリを作成するには、Firebase Authentication、FirebaseUI、CloudFirestoreライブラリを使用します。このコードラボでは、次のインポートステートメントがindex.js
ファイルの先頭にすでに含まれています。今後、各Firebaseライブラリからさらに多くのメソッドをインポートします。
// Import stylesheets
import './style.css';
// Firebase App (the core Firebase SDK) is always required
import { initializeApp } from 'firebase/app';
// Add the Firebase products and methods that you want to use
import {} from 'firebase/auth';
import {} from 'firebase/firestore';
import * as firebaseui from 'firebaseui';
FirebaseWebアプリをFirebaseプロジェクトに追加します
- Firebaseコンソールに戻り、左上の[プロジェクトの概要]をクリックして、プロジェクトの概要ページに移動します。
- プロジェクトの概要ページの中央にあるWebアイコンをクリックします
新しいFirebaseWebアプリを作成します。
- ニックネームWebAppでアプリを登録します。
- このコードラボでは、[このアプリのFirebaseホスティングも設定する]の横にあるチェックボックスをオンにしないでください。ここでは、StackBlitzのプレビューペインを使用します。
- [アプリの登録]をクリックします。
- Firebase設定オブジェクトをクリップボードにコピーします。
- [続行]をクリックしてコンソールに移動します。Firebase構成オブジェクトをアプリに追加します。
- StackBlitzに戻り、
index.js
ファイルに移動します。 -
Add Firebase project configuration object here
コメント行を見つけて、コメントのすぐ下に構成スニペットを貼り付けます。 -
initializeApp
関数呼び出しを追加して、独自のFirebaseプロジェクト構成を使用してFirebaseをセットアップします。// ... // Add Firebase project configuration object here const firebaseConfig = { apiKey: "random-unique-string", authDomain: "your-projectId.firebaseapp.com", databaseURL: "https://your-projectId.firebaseio.com", projectId: "your-projectId", storageBucket: "your-projectId.appspot.com", messagingSenderId: "random-unique-string", appId: "random-unique-string", }; // Initialize Firebase initializeApp(firebaseConfig);
6.ユーザーサインイン(RSVP)を追加します
アプリにFirebaseを追加したので、 Firebase認証を使用してユーザーを登録するRSVPボタンを設定できます。
電子メールサインインとFirebaseUIを使用してユーザーを認証します
ユーザーにメールアドレスでサインインするように求めるRSVPボタンが必要です。これを行うには、 FirebaseUIをRSVPボタンに接続します。FirebaseUIは、FirebaseAuthの上に構築済みのUIを提供するライブラリです。
FirebaseUIには、次の2つのことを行う構成(ドキュメントのオプションを参照)が必要です。
- 電子メール/パスワードのサインイン方法を使用することをFirebaseUIに通知します。
- サインインが成功した場合のコールバックを処理し、リダイレクトを回避するためにfalseを返します。単一ページのWebアプリを構築しているため、ページを更新したくありません。
FirebaseUIAuthを初期化するコードを追加します
- StackBlitzで、
index.js
ファイルに移動します。 - 上部で、firebase
firebase/auth
importステートメントを見つけてから、次のようにgetAuth
とEmailAuthProvider
を追加します。l10n// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider } from 'firebase/auth'; import {} from 'firebase/firestore';
- 次のように、
initializeApp
の直後に認証オブジェクトへの参照を保存しますinitializeApp(firebaseConfig); auth = getAuth();
- FirebaseUI構成が開始コードですでに提供されていることに注意してください。電子メール認証プロバイダーを使用するように既に設定されています。
-
index.js
のmain()
関数の下部に、次のようにFirebaseUI初期化ステートメントを追加しますasync function main() { // ... // Initialize the FirebaseUI widget using Firebase const ui = new firebaseui.auth.AuthUI(auth); } main();
HTMLにRSVPボタンを追加します
- StackBlitzで、
index.html
ファイルに移動します。 - 次の例に示すように、
event-details-container
内にRSVPボタンのHTMLを追加します。
このコードラボでは、index.js
ファイルにこれらの特定のIDのフックがすでに存在するため、以下に示すのと同じid
値を使用するように注意してください。
index.html
ファイルには、IDがfirebaseui-auth-container
のコンテナーがあることに注意してください。これは、ログインを保持するためにFirebaseUIに渡すIDです。
アプリのプレビュー<!-- ... --> <section id="event-details-container"> <!-- ... --> <!-- ADD THE RSVP BUTTON HERE --> <button id="startRsvp">RSVP</button> </section> <hr> <section id="firebaseui-auth-container"></section> <!-- ... -->
- RSVPボタンでリスナーを設定し、FirebaseUI開始関数を呼び出します。これにより、FirebaseUIにサインインウィンドウを表示するように指示されます。
index.js
のmain()
関数の下部に次のコードを追加します:async function main() { // ... // Listen to RSVP button clicks startRsvpButton.addEventListener("click", () => { ui.start("#firebaseui-auth-container", uiConfig); }); } main();
アプリへのサインインをテストする
- StackBlitzのプレビューウィンドウで、[出欠確認]ボタンをクリックしてアプリにサインインします。
- このコードラボでは、このコードラボの電子メール検証手順を設定していないため、偽の電子メールアドレスを含め、任意の電子メールアドレスを使用できます。
-
auth/operation-not-allowed
またはThe given sign-in provider is disabled for this Firebase project
いることを示すエラーメッセージが表示された場合は、FirebaseコンソールでサインインプロバイダーとしてEメール/パスワードが有効になっていることを確認してください。
- Firebaseコンソールの認証ダッシュボードに移動します。 [ユーザー]タブに、アプリにサインインするために入力したアカウント情報が表示されます。
UIに認証状態を追加する
次に、UIにサインインしているという事実が反映されていることを確認します。
Firebase Authentication状態リスナーコールバックを使用します。このコールバックは、ユーザーのログインステータスが変更されるたびに通知されます。現在サインインしているユーザーがいる場合、アプリは[RSVP]ボタンを[ログアウト]ボタンに切り替えます。
- StackBlitzで、
index.js
ファイルに移動します。 - 上部で、firebase
firebase/auth
importステートメントを見つけてから、signOut
とonAuthStateChanged
を次のように追加します。l10n// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import {} from 'firebase/firestore';
-
main()
関数の下部に次のコードを追加します:async function main() { // ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; } else { startRsvpButton.textContent = 'RSVP'; } }); } main();
- ボタンリスナーで、現在のユーザーがいるかどうかを確認し、ログアウトします。これを行うには、現在の
startRsvpButton.addEventListener
を次のように置き換えます。l10n// ... // Called when the user clicks the RSVP button startRsvpButton.addEventListener('click', () => { if (auth.currentUser) { // User is signed in; allows user to sign out signOut(auth); } else { // No user is signed in; allows user to sign in ui.start('#firebaseui-auth-container', uiConfig); } });
これで、アプリのボタンにLOGOUTと表示され、クリックするとRSVPに戻るはずです。
アプリのプレビュー
7.CloudFirestoreにメッセージを書き込みます
ユーザーが来ていることを知っているのは素晴らしいことですが、ゲストにアプリで何か他のことをしてもらいましょう。ゲストブックにメッセージを残すことができたらどうでしょうか。彼らは、なぜ彼らが来ることに興奮しているのか、誰に会いたいのかを共有することができます。
ユーザーがアプリに書き込んだチャットメッセージを保存するには、 CloudFirestoreを使用します。
データ・モデル
Cloud FirestoreはNoSQLデータベースであり、データベースに格納されているデータは、コレクション、ドキュメント、フィールド、およびサブコレクションに分割されます。チャットの各メッセージは、 guestbook
と呼ばれるトップレベルのコレクションにドキュメントとして保存されます。
Firestoreにメッセージを追加する
このセクションでは、ユーザーがデータベースに新しいメッセージを書き込むための機能を追加します。まず、UI要素(メッセージフィールドと送信ボタン)のHTMLを追加します。次に、これらの要素をデータベースに接続するコードを追加します。
メッセージフィールドと送信ボタンのUI要素を追加するには:
- StackBlitzで、
index.html
ファイルに移動します。 -
guestbook-container
を見つけ、次のHTMLを追加して、メッセージ入力フィールドと送信ボタンを備えたフォームを作成します。<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form id="leave-message"> <label>Leave a message: </label> <input type="text" id="message"> <button type="submit"> <i class="material-icons">send</i> <span>SEND</span> </button> </form> </section> <!-- ... -->
アプリのプレビュー
ユーザーが[送信]ボタンをクリックすると、以下のコードスニペットがトリガーされます。メッセージ入力フィールドの内容をデータベースのguestbook
コレクションに追加します。具体的には、 addDoc
メソッドは、メッセージコンテンツを(自動的に生成されたIDを持つ)新しいドキュメントのguestbook
コレクションに追加します。
- StackBlitzで、
index.js
ファイルに移動します。 - 上部で、firebase
firebase/firestore
importステートメントを見つけてから、getFirestore
、addDoc
、collection
を次のように追加します。l10n// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, addDoc, collection } from 'firebase/firestore';
- ここで、
initializeApp
の直後にFirestoredb
オブジェクトへの参照を保存します:initializeApp(firebaseConfig); auth = getAuth(); db = getFirestore();
-
main()
関数の下部に、次のコードを追加します。
auth.currentUser.uid
は、FirebaseAuthenticationがログインしているすべてのユーザーに提供する自動生成された一意のIDへの参照であることに注意してください。async function main() { // ... // Listen to the form submission form.addEventListener('submit', async e => { // Prevent the default form redirect e.preventDefault(); // Write a new message to the database collection "guestbook" addDoc(collection(db, 'guestbook'), { text: input.value, timestamp: Date.now(), name: auth.currentUser.displayName, userId: auth.currentUser.uid }); // clear message input field input.value = ''; // Return false to avoid redirect return false; }); } main();
サインインしたユーザーにのみゲストブックを表示する
誰にもゲストのチャットを見せたくない。チャットを保護するためにできることの1つは、サインインしたユーザーだけがゲストブックを表示できるようにすることです。とはいえ、独自のアプリの場合は、 Firebaseセキュリティルールを使用してデータベースも保護する必要があります。 (セキュリティルールの詳細については、コードラボの後半にあります。)
- StackBlitzで、
index.js
ファイルに移動します。 -
onAuthStateChanged
リスナーを編集して、ゲストブックを表示および非表示にします。// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; } });
メッセージの送信をテストする
- アプリにサインインしていることを確認してください。
- 「Heythere!」などのメッセージを入力し、[送信]をクリックします。
このアクションにより、メッセージがCloudFirestoreデータベースに書き込まれます。ただし、データの取得を実装する必要があるため、実際のWebアプリにはまだメッセージが表示されません。次にそれを行います。
ただし、Firebaseコンソールで新しく追加されたメッセージを確認できます。
FirebaseコンソールのFirestoreデータベースダッシュボードに、新しく追加されたメッセージを含むguestbook
コレクションが表示されます。メッセージを送信し続けると、ゲストブックコレクションには次のような多くのドキュメントが含まれます。
Firebaseコンソール
8.メッセージを読む
メッセージを同期する
ゲストがデータベースにメッセージを書き込むことができるのは素晴らしいことですが、アプリではまだメッセージを見ることができません。
メッセージを表示するには、データが変更されたときにトリガーするリスナーを追加してから、新しいメッセージを表示するUI要素を作成する必要があります。
アプリから新しく追加されたメッセージをリッスンするコードを追加します。まず、メッセージを表示するセクションをHTMLに追加します。
- StackBlitzで、
index.html
ファイルに移動します。 -
guestbook-container
に、guestbook
のIDを持つ新しいセクションを追加します。<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form><!-- ... --></form> <section id="guestbook"></section> </section> <!-- ... -->
次に、データに加えられた変更をリッスンするリスナーを登録します。
- StackBlitzで、
index.js
ファイルに移動します。 - 上部で、firebase
firebase/firestore
importステートメントを見つけてから、次のようにquery
、orderBy
、onSnapshot
を追加します。l10n// ... import { getFirestore, addDoc, collection, query, orderBy, onSnapshot } from 'firebase/firestore';
-
main()
関数の下部に、データベース内のすべてのドキュメント(ゲストブックメッセージ)をループする次のコードを追加します。このコードで何が起こっているかについて詳しくは、スニペットの下の情報をお読みください。async function main() { // ... // Create query for messages const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); } main();
データベース内のメッセージをリッスンするために、 collection
関数を使用して特定のコレクションに対するクエリを作成しました。上記のコードは、チャットメッセージが保存されるguestbook
コレクションの変更をリッスンします。メッセージは、 orderBy('timestamp', 'desc')
を使用して日付順に並べられ、最新のメッセージが上部に表示されます。
onSnapshot
関数は、使用するクエリとコールバック関数の2つのパラメーターを取ります。クエリに一致するドキュメントに変更があった場合、コールバック関数がトリガーされます。これは、メッセージが削除、変更、または追加された場合に発生する可能性があります。詳細については、 CloudFirestoreのドキュメントを参照してください。
同期メッセージをテストする
Cloud Firestoreは、データベースにサブスクライブしているクライアントとデータを自動的かつ瞬時に同期します。
- データベースで以前に作成したメッセージは、アプリに表示されます。新しいメッセージを自由に書いてください。それらはすぐに表示されるはずです。
- ワークスペースを複数のウィンドウまたはタブで開くと、メッセージはタブ間でリアルタイムに同期されます。
- (オプション) Firebaseコンソールの[データベース]セクションで、新しいメッセージを手動で直接削除、変更、または追加してみることができます。変更はUIに表示されます。
おめでとう!アプリでCloudFirestoreドキュメントを読んでいます!
アプリのプレビュー
9.基本的なセキュリティルールを設定します
最初に、テストモードを使用するようにCloud Firestoreを設定しました。これは、データベースが読み取りと書き込みのために開いていることを意味します。ただし、テストモードは、開発のごく初期の段階でのみ使用する必要があります。ベストプラクティスとして、アプリを開発するときにデータベースのセキュリティルールを設定する必要があります。セキュリティは、アプリの構造と動作に不可欠である必要があります。
セキュリティルールを使用すると、データベース内のドキュメントとコレクションへのアクセスを制御できます。柔軟なルール構文を使用すると、データベース全体へのすべての書き込みから特定のドキュメントの操作まで、あらゆるものに一致するルールを作成できます。
CloudFirestoreのセキュリティルールはFirebaseコンソールで作成できます。
- Firebaseコンソールの[ビルド]セクションで、[ Firestoreデータベース]をクリックし、[ルール]タブを選択します(または、ここをクリックして[ルール]タブに直接移動します)。
- 次のデフォルトのセキュリティルールが表示されます。パブリックアクセスの制限時間は、今日から数週間です。
コレクションを特定する
まず、アプリがデータを書き込むコレクションを特定します。
- 既存の
match /{document=**}
句を削除して、ルールが次のようになるようにしますrules_version = '2'; service cloud.firestore { match /databases/{database}/documents { } }
-
match /databases/{database}/documents
で、保護するコレクションを特定します:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { // You'll add rules here in the next step. } }
セキュリティルールを追加する
各ゲストブックドキュメントのフィールドとして認証UIDを使用したため、認証UIDを取得して、ドキュメントに書き込もうとしているユーザーが一致する認証UIDを持っていることを確認できます。
- 次に示すように、読み取りルールと書き込みルールをルールセットに追加します
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId; } } }
- [公開]をクリックして新しいルールを展開します。これで、ゲストブックの場合、サインインしたユーザーのみがメッセージを読むことができます(任意のメッセージ!)が、ユーザーIDを使用してのみメッセージを作成できます。また、メッセージを編集または削除することも許可されていません。
検証ルールを追加する
- データ検証を追加して、予期されるすべてのフィールドがドキュメントに存在することを確認します:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId && "name" in request.resource.data && "text" in request.resource.data && "timestamp" in request.resource.data; } } }
- [公開]をクリックして、新しいルールを展開します。
リスナーをリセット
アプリでは認証されたユーザーのみがログインできるようになったため、ゲストブックのfirestore
クエリを認証リスナー内に移動する必要があります。そうしないと、権限エラーが発生し、ユーザーがログアウトしたときにアプリが切断されます。
- StackBlitzで、
index.js
ファイルに移動します。 - ゲストブックコレクション
onSnapshot
リスナーをsubscribeGuestbook
という新しい関数にプルします。また、onSnapshot
関数の結果をguestbookListener
変数に割り当てます。
FirestoreonSnapshot
リスナーは、後でスナップショットリスナーをキャンセルするために使用できる購読解除関数を返します。// ... // Listen to guestbook updates function subscribeGuestbook() { const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); guestbookListener = onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); }
-
unsubscribeGuestbook
という新しい関数を下に追加します。guestbookListener
変数がnullでないかどうかを確認してから、関数を呼び出してリスナーをキャンセルします。// ... // Unsubscribe from guestbook updates function unsubscribeGuestbook() { if (guestbookListener != null) { guestbookListener(); guestbookListener = null; } }
最後に、新しい関数をonAuthStateChanged
コールバックに追加します。
-
if (user)
の下部にsubscribeGuestbook()
を追加します。 -
else
ステートメントの最後にunsubscribeGuestbook()
を追加します。// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); } });
10.ボーナスステップ:学んだことを実践する
出席者の出欠確認ステータスを記録する
現在、このアプリでは、イベントに興味がある場合にチャットを開始できます。また、誰かが来ているかどうかを知る唯一の方法は、チャットに投稿するかどうかです。整理して、何人の人が来るのかを知らせましょう。
トグルを追加して、イベントに参加したい人を登録し、来ている人の数を収集します。
- StackBlitzで、
index.html
ファイルに移動します。 -
guestbook-container
に、次のようにYESボタンとNOボタンのセットを追加します<!-- ... --> <section id="guestbook-container"> <h2>Are you attending?</h2> <button id="rsvp-yes">YES</button> <button id="rsvp-no">NO</button> <h2>Discussion</h2> <!-- ... --> </section> <!-- ... -->
アプリのプレビュー
次に、ボタンクリックのリスナーを登録します。ユーザーが[はい]をクリックした場合は、認証UIDを使用して応答をデータベースに保存します。
- StackBlitzで、
index.js
ファイルに移動します。 - 上部で、firebase
firebase/firestore
importステートメントを見つけてから、doc
、setDoc
、およびwhere
追加します。たとえば、次のようになります。l10n// ... // Add the Firebase products and methods that you want to use import { getFirestore, addDoc, collection, query, orderBy, onSnapshot, doc, setDoc, where } from 'firebase/firestore';
-
main()
関数の下部に、RSVPステータスをリッスンする次のコードを追加しますasync function main() { // ... // Listen to RSVP responses rsvpYes.onclick = async () => { }; rsvpNo.onclick = async () => { }; } main();
- 次に、
attendees
と呼ばれる新しいコレクションを作成し、いずれかのRSVPボタンがクリックされた場合にドキュメント参照を登録します。クリックされたボタンに応じて、その参照をtrue
またはfalse
に設定します。
まず、rsvpYes
の場合:
次に、// ... // Listen to RSVP responses rsvpYes.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attendi()ng: true try { await setDoc(userRef, { attending: true }); } catch (e) { console.error(e); } };
rsvpNo
の場合も同じですが、値はfalse
です:rsvpNo.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attending: true try { await setDoc(userRef, { attending: false }); } catch (e) { console.error(e); } };
セキュリティルールを更新する
すでにいくつかのルールが設定されているため、ボタンを使用して追加する新しいデータは拒否されます。
attendees
コレクションへの追加を許可する
attendees
コレクションに追加できるようにルールを更新する必要があります。
-
attendees
コレクションの場合、ドキュメント名として認証UIDを使用したため、それを取得して、送信者のuid
が作成中のドキュメントと同じであることを確認できます。参加者リストは誰でも読むことができますが(プライベートデータがないため)、更新できるのは作成者だけです。rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId; } } }
- [公開]をクリックして、新しいルールを展開します。
検証ルールを追加する
- いくつかのデータ検証ルールを追加して、予期されるすべてのフィールドがドキュメントに存在することを確認します
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId && "attending" in request.resource.data; } } }
- ルールを展開するには、[公開]をクリックすることを忘れないでください。
(オプション)ボタンをクリックした結果を表示できるようになりました。 FirebaseコンソールでCloudFirestoreダッシュボードに移動します。
RSVPステータスを読み取る
応答を記録したので、誰が来るのかを確認し、UIに反映させましょう。
- StackBlitzで、
index.html
ファイルに移動します。 -
description-container
に、number-attending
のIDを持つ新しい要素を追加します。<!-- ... --> <section id="description-container"> <!-- ... --> <p id="number-attending"></p> </section> <!-- ... -->
次に、 attendees
コレクションのリスナーを登録し、 YES応答の数を数えます。
- StackBlitzで、
index.js
ファイルに移動します。 -
main()
関数の下部に、次のコードを追加して、RSVPステータスをリッスンし、 YESクリックをカウントします。async function main() { // ... // Listen for attendee list const attendingQuery = query( collection(db, 'attendees'), where('attending', '==', true) ); const unsubscribe = onSnapshot(attendingQuery, snap => { const newAttendeeCount = snap.docs.length; numberAttending.innerHTML = newAttendeeCount + ' people going'; }); } main();
最後に、現在のステータスに対応するボタンを強調表示しましょう。
- 現在の認証UIDが
attendees
コレクションにエントリを持っているかどうかをチェックする関数を作成し、ボタンクラスをclicked
に設定します。// ... // Listen for attendee list function subscribeCurrentRSVP(user) { const ref = doc(db, 'attendees', user.uid); rsvpListener = onSnapshot(ref, doc => { if (doc && doc.data()) { const attendingResponse = doc.data().attending; // Update css classes for buttons if (attendingResponse) { rsvpYes.className = 'clicked'; rsvpNo.className = ''; } else { rsvpYes.className = ''; rsvpNo.className = 'clicked'; } } }); }
- また、退会する機能を作ってみましょう。これは、ユーザーがログアウトするときに使用されます。
// ... function unsubscribeCurrentRSVP() { if (rsvpListener != null) { rsvpListener(); rsvpListener = null; } rsvpYes.className = ''; rsvpNo.className = ''; }
- 認証リスナーから関数を呼び出します。
// ... // Listen to the current Auth state // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); // Subcribe to the user's RSVP subscribeCurrentRSVP(user); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none' ; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); // Unsubscribe from the guestbook collection unsubscribeCurrentRSVP(); } });
- 複数のユーザーとしてログインしてみて、[はい]ボタンをクリックするたびにカウントが増えることを確認してください。
アプリのプレビュー
11.おめでとうございます!
Firebaseを使用して、インタラクティブなリアルタイムWebアプリケーションを構築しました。
私たちがカバーしたこと
- Firebase認証
- FirebaseUI
- CloudFirestore
- Firebaseのセキュリティルール
次のステップ
- Firebase Developerワークフローについて詳しく知りたいですか?アプリを完全にローカルでテストして実行する方法については、 Firebaseエミュレータコードラボをご覧ください。
- 他のFirebase製品についてもっと知りたいですか?ユーザーがアップロードした画像ファイルを保存したいですか?または、ユーザーに通知を送信しますか? Firebase Webコードラボで、さらに多くのWeb用Firebase製品について詳しく説明しているコードラボを確認してください。
- Cloud Firestoreについてもっと知りたいですか?サブコレクションとトランザクションについて知りたいですか? Cloud Firestoreの詳細については、CloudFirestoreWebコードラボにアクセスしてください。または、このYouTubeシリーズをチェックして、CloudFirestoreについて理解してください。
もっと詳しく知る
- Firebaseサイト: firebase.google.com
- FirebaseYouTubeチャンネル
どうだった?
フィードバックをお待ちしております。こちらの(非常に)短いフォームに記入してください。