1。概要
このコードラボでは、インタラクティブな Web アプリケーションを作成するためのFirebaseの基本のいくつかを学びます。いくつかの Firebase 製品を使用して、イベントの出欠確認とゲストブック チャット アプリを構築します。
学べること
- Firebase Authentication と FirebaseUI を使用してユーザーを認証します。
- Cloud Firestore を使用してデータを同期します。
- データベースを保護するために Firebase セキュリティ ルールを作成します。
必要なもの
- Chrome などの任意のブラウザ。
- stackblitz.comにアクセスします (アカウントやサインインは必要ありません)。
- Gmail アカウントのような Google アカウント。 GitHub アカウントに既に使用している電子メール アカウントをお勧めします。これにより、StackBlitz の高度な機能を使用できるようになります。
- コードラボのサンプルコード。コードを取得する方法については、次のステップを参照してください。
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 の利用規約に同意します。このアプリでは Analytics を使用しないため、Google Analytics 画面で [有効にしない] をクリックします。
Firebase プロジェクトの詳細については、 「Firebase プロジェクトを理解する」を参照してください。
コンソールで Firebase 製品を有効にして設定する
構築しているアプリは、ウェブアプリで利用できるいくつかの Firebase 製品を使用しています。
- Firebase AuthenticationとFirebase UIにより、ユーザーがアプリに簡単にサインインできるようになります。
- Cloud Firestore は、構造化データをクラウド上に保存し、データが変更されたときに即座に通知を受け取ります。
- データベースを保護するためのFirebase セキュリティ ルール。
これらの製品の中には、特別な構成が必要な場合や、Firebase コンソールを使用して有効にする必要があるものもあります。
Firebase Authentication のメール サインインを有効にする
ユーザーが Web アプリにサインインできるようにするには、このコードラボではメール/パスワードによるサインイン方法を使用します。
- Firebase コンソールの左側のパネルで、 [ビルド] > [認証]をクリックします。次に、 「開始する」をクリックします。これで、認証ダッシュボードが表示され、サインアップしたユーザーの表示、サインイン プロバイダーの構成、および設定の管理を行うことができます。
- [サインイン方法]タブを選択します (または、ここをクリックしてタブに直接移動します)。
- プロバイダー オプションから[電子メール/パスワード]をクリックし、スイッチを[有効]に切り替えて、 [保存]をクリックします。
Cloud Firestore をセットアップする
このウェブアプリはCloud Firestoreを使用してチャット メッセージを保存し、新しいチャット メッセージを受信します。
Cloud Firestore を設定する方法は次のとおりです。
- Firebase コンソールの左側のパネルで、 [構築] > [Firestore データベース]をクリックします。次に、 「データベースの作成」をクリックします。
- [データベースの作成]をクリックします。
- 「テストモードで開始」オプションを選択します。セキュリティ ルールに関する免責事項をお読みください。テスト モードでは、開発中にデータベースに自由に書き込むことができます。 「次へ」をクリックします。
- データベースの場所を選択します (デフォルトをそのまま使用できます)。ただし、この場所は後で変更できないことに注意してください。
- 「完了」をクリックします。
5. Firebaseの追加と構成
Firebase プロジェクトを作成し、いくつかのサービスを有効にしたので、コードに Firebase を使用することと、どの Firebase プロジェクトを使用するかを指示する必要があります。
Firebase ライブラリを追加する
アプリで Firebase を使用するには、Firebase ライブラリをアプリに追加する必要があります。 Firebase のドキュメント で説明されているように、これを行うには複数の方法があります。たとえば、Google の CDN からライブラリを追加したり、Browserify を使用している場合は npm を使用してライブラリをローカルにインストールし、アプリにパッケージ化したりできます。
StackBlitz は自動バンドルを提供するため、import ステートメントを使用して Firebase ライブラリを追加できます。モジュール (v9) バージョンのライブラリを使用します。これは、「ツリー シェーキング」と呼ばれるプロセスを通じて Web ページ全体のサイズを縮小するのに役立ちます。モジュラー SDK の詳細については、ドキュメントを参照してください。
このアプリを構築するには、Firebase Authentication、FirebaseUI、Cloud Firestore ライブラリを使用します。このコードラボでは、次のインポート ステートメントが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';
Firebase ウェブアプリを Firebase プロジェクトに追加する
- Firebase コンソールに戻り、左上の [プロジェクトの概要] をクリックしてプロジェクトの概要ページに移動します。
- プロジェクトの概要ページの中央にある Web アイコンをクリックします。
新しい Firebase ウェブアプリを作成します。
- アプリをWeb Appというニックネームで登録します。
- このコードラボでは、 [このアプリの Firebase Hosting も設定する]の横のボックスをオンにしないでください。ここでは、StackBlitz のプレビュー ペインを使用します。
- [アプリの登録]をクリックします。
- Firebase 構成オブジェクトをクリップボードにコピーします。
- [コンソールに進む]をクリックします。Firebase 構成オブジェクトをアプリに追加します。
- StackBlitz に戻り、
index.js
ファイルに移動します。 -
Add Firebase project configuration object here
というコメント行を見つけて、そのコメントのすぐ下に設定スニペットを貼り付けます。 - 独自の Firebase プロジェクト構成を使用して Firebase をセットアップするには、
initializeApp
関数呼び出しを追加します。// ... // 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 Authenticationを使用してユーザーを登録する RSVP ボタンを設定できます。
電子メール サインインと FirebaseUI を使用してユーザーを認証する
ユーザーに電子メール アドレスでのサインインを求める [RSVP] ボタンが必要です。これを行うには、 FirebaseUI をRSVP ボタンに接続します。FirebaseUI は、Firebase Auth 上に事前構築された UI を提供するライブラリです。
FirebaseUI には、次の 2 つのことを行う構成 (ドキュメントのオプションを参照) が必要です。
- FirebaseUI にメール/パスワードによるサインイン方法を使用するように指示します。
- サインインが成功した場合のコールバックを処理し、リダイレクトを回避するために false を返します。シングルページの Web アプリを構築しているため、ページを更新したくないとします。
FirebaseUI Auth を初期化するコードを追加します
- StackBlitz で、
index.js
ファイルに移動します。 - 上部で
firebase/auth
import ステートメントを見つけて、
のように// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider } from 'firebase/auth'; import {} from 'firebase/firestore';
getAuth
とEmailAuthProvider
を追加します。 - 次のように、
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
ファイルには、firebaseui-auth-container
ID を持つコンテナーがあることに注意してください。これは、ログインを保持するために 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 のプレビュー ウィンドウで、[RSVP] ボタンをクリックしてアプリにサインインします。
- このコードラボでは電子メール検証手順を設定していないため、偽の電子メール アドレスであっても、任意の電子メール アドレスを使用できます。
-
auth/operation-not-allowed
またはThe given sign-in provider is disabled for this Firebase project
というエラー メッセージが表示された場合は、Firebase コンソールでサインイン プロバイダとしてメール/パスワードが有効になっていることを確認してください。
- Firebase コンソールの認証ダッシュボードに移動します。 [ユーザー]タブに、アプリにサインインするために入力したアカウント情報が表示されます。
認証状態を UI に追加する
次に、サインインしていることが UI に反映されていることを確認します。
Firebase Authentication 状態リスナー コールバックを使用します。これは、ユーザーのサインイン ステータスが変化するたびに通知を受け取ります。現在サインインしているユーザーがいる場合、アプリは「出欠確認」ボタンを「ログアウト」ボタンに切り替えます。
- StackBlitz で、
index.js
ファイルに移動します。 - 上部で
firebase/auth
import ステートメントを見つけて、
のように// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import {} from 'firebase/firestore';
signOut
とonAuthStateChanged
追加します。 -
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
次のものに置き換えます:// ... // 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. Cloud Firestore にメッセージを書き込む
ユーザーが来ることがわかっているのは素晴らしいことですが、アプリ内でゲストに何か他のことをしてもらいましょう。ゲストブックにメッセージを残せたらどうなるでしょうか?なぜ来ることに興奮しているのか、誰に会いたいのかを共有できます。
ユーザーがアプリに書いたチャット メッセージを保存するには、 Cloud Firestore を使用します。
データ・モデル
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> <!-- ... -->
アプリのプレビュー
ユーザーが[SEND]ボタンをクリックすると、以下のコード スニペットがトリガーされます。メッセージ入力フィールドの内容をデータベースのguestbook
コレクションに追加します。具体的には、 addDoc
メソッドは、 guestbook
コレクションの新しいドキュメント (自動生成された ID を持つ) にメッセージ コンテンツを追加します。
- StackBlitz で、
index.js
ファイルに移動します。 - 上部で
firebase/firestore
import ステートメントを見つけて、
のように// ... // 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';
getFirestore
、addDoc
、collection
を追加します。 - 次に、
initializeApp
直後に Firestoredb
オブジェクトへの参照を保存します:initializeApp(firebaseConfig); auth = getAuth(); db = getFirestore();
-
main()
関数の最後に、次のコードを追加します。
auth.currentUser.uid
、Firebase Authentication がログインしているすべてのユーザーに与える自動生成された一意の 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'; } });
メッセージ送信のテスト
- アプリにサインインしていることを確認してください。
- 「こんにちは!」などのメッセージを入力し、 [送信]をクリックします。
このアクションにより、メッセージが Cloud Firestore データベースに書き込まれます。ただし、データの取得を実装する必要があるため、実際の 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/firestore
import ステートメントを見つけて、
のように// ... import { getFirestore, addDoc, collection, query, orderBy, onSnapshot } from 'firebase/firestore';
query
、orderBy
、およびonSnapshot
を追加します。 -
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 つのパラメータを取ります。コールバック関数は、クエリに一致するドキュメントに変更があったときにトリガーされます。これは、メッセージが削除、変更、または追加された場合に発生する可能性があります。詳細については、 Cloud Firestore のドキュメントを参照してください。
メッセージの同期をテストする
Cloud Firestore は、データベースに登録しているクライアントとデータを自動的かつ即座に同期します。
- データベース内に以前に作成したメッセージがアプリに表示されるはずです。気軽に新しいメッセージを書いてください。それらは即座に表示されるはずです。
- ワークスペースを複数のウィンドウまたはタブで開くと、メッセージはタブ間でリアルタイムに同期されます。
- (オプション) Firebase コンソールの[データベース]セクションで直接、手動でメッセージを削除、変更、または新しいメッセージを追加してみることができます。変更があれば UI に表示されるはずです。
おめでとう!アプリで Cloud Firestore ドキュメントを読んでいます。
アプリのプレビュー
9. 基本的なセキュリティルールを設定する
最初にテスト モードを使用するように Cloud Firestore を設定します。これは、データベースが読み取りと書き込みのために開いていることを意味します。ただし、テスト モードは開発の非常に初期段階でのみ使用してください。ベスト プラクティスとして、アプリの開発時にデータベースのセキュリティ ルールを設定する必要があります。セキュリティはアプリの構造と動作に不可欠である必要があります。
セキュリティ ルールを使用すると、データベース内のドキュメントやコレクションへのアクセスを制御できます。柔軟なルール構文を使用すると、データベース全体へのすべての書き込みから特定のドキュメントの操作まで、あらゆるものに一致するルールを作成できます。
Firebase コンソールで Cloud Firestore のセキュリティ ルールを作成できます。
- 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
リスナーは、後でスナップショット リスナーをキャンセルするために使用できる unsubscribe 関数を返します。// ... // 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/firestore
import ステートメントを見つけて、
のように// ... // Add the Firebase products and methods that you want to use import { getFirestore, addDoc, collection, query, orderBy, onSnapshot, doc, setDoc, where } from 'firebase/firestore';
doc
、setDoc
、およびwhere
を追加します。 -
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 コンソールで Cloud Firestore ダッシュボードに移動します。
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
- クラウドファイアストア
- Firebase セキュリティ ルール
次のステップ
- Firebase 開発者のワークフローについて詳しく知りたいですか?アプリを完全にローカルでテストして実行する方法については、Firebase エミュレータのコードラボを確認してください。
- 他の Firebase 製品について詳しく知りたいですか?ユーザーがアップロードした画像ファイルを保存したいと考えていませんか?それともユーザーに通知を送信しますか?他の多くのウェブ用 Firebase 製品についてさらに詳しく説明したコードラボについては、Firebase ウェブ コードラボをご覧ください。
- Cloud Firestore について詳しく知りたいですか?サブコレクションとトランザクションについて知りたいですか? Cloud Firestore についてさらに詳しく説明したコードラボについては、Cloud Firestore ウェブ コードラボにアクセスしてください。または、このYouTube シリーズをチェックして Cloud Firestore について理解してください。
もっと詳しく知る
- Firebase サイト: firebase.google.com
- Firebase YouTube チャンネル
どうだった?
ぜひフィードバックをお待ちしております。こちらの(非常に)短いフォームにご記入ください。