🔥

【Cloud Firestore×React】Hooksにして最新データを自動fetchする

2022/10/12に公開

このあいだの【Firebase Authentication×React】ログイン中かどうかで画面を分けるの関連。

Firebase Cloud Firestoreのリアルタイム更新検知機能を使って、最新のデータを常に取得&表示したいようなケースでも、ReactだとHooksにしてしまうのが基本楽かなと。

たとえば Contents コレクションに Content { name:string, score:number } みたいなドキュメントを管理しているとして、ID指定で Content の最新データを参照したい場合を例として。

ついでにいうと、Firestoreのコレクションやドキュメントを参照するパスはあっちこっちにちらかりがちなので(サブコレクションとかreferenceがあると特に)一か所で管理する↓こんなやつを作っておくのがおすすめです。
TypeScriptの場合はここでDocumentの型付けもしておく。

export interface Content {
  name: string;
  score: number;
}

class StoragePathService {
    private readonly db = getFirestore();

    public contents = () => collection(this.db, "Contents") as CollectionReference<Content>;
    public content = (id: string) => doc(this.db, "Contents", id) as DocumentReference<Content>;
}

export const storagePathService = new StoragePathService();

以下が本題の、最新データを使うHooks。
内部で onSnapshot をsubscribeする。

export const useContent = (contentId: string) => {
    const [ content, setContent ] = useState<Content>();

    useEffect(() => {
        const unsub = onSnapshot(storagePathService.content(contentId), doc => {
            return setContent(doc.data());
        })

        return unsub;

    }, [ contentId ]);

    return content;
}

使う側コンポーネントはこんなイメージ。

export const ContentDisplay = (props: { contentId: string }) => {
    const content = useContent(props.contentId);

    if (content == null) {
        return <></>
    }

    return (
        <div>
            <div>{content.name}</div>
            <div>{content.description}</div>
        </div>
    )
}

自前でリロードやポーリングを実装する必要がないのは楽ですね。

Discussion