はじめに
前回の記事でreact-firebase-hooksのAuth Hooksを使ってみたのですが、今回はFirestore Hooksに挑戦したいと思います。
react-firebase-hooks
リポジトリはこちらです。
https://github.com/CSFrequency/react-firebase-hooks
このライブラリは、4種類のAPIを提供しています。
- Auth Hooks
- Cloud Firestore Hooks
- Cloud Storage Hooks
- Realtime Database Hooks
今回対象とするのは2つ目のFirestore Hooksです。
テストデータの作成
最初に、Firestoreのコンソールでコレクションといくつかのドキュメントを作成します。コレクション名はtodosとしました。
コーディング
モジュールのimport
今回使うモジュールをimportします。
import React, { useState } from "react";
import ReactDOM from "react-dom";
import firebase from "firebase";
import { useCollectionData } from "react-firebase-hooks/firestore";
TodoListコンポーネント
todosコレクションを表示するコンポーネントを作ります。
const TodoList = () => {
const [values, loading, error] = useCollectionData(
firebase.firestore().collection("todos"),
{ idField: "id" }
);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>{`Error: ${error.message}`}</div>;
}
return (
<ul>
{values.map(value => (
<li key={value.id}>{value.title}</li>
))}
</ul>
);
};
idField
でidを取得するところがポイントです。
NewTodoコンポーネント
todosコレクションに新たなドキュメントを追加するためのコンポーネントを作ります。
const NewTodo = () => {
const [title, setTitle] = useState("");
const [pending, setPending] = useState(false);
const add = async () => {
setTitle("");
setPending(true);
try {
await firebase
.firestore()
.collection("todos")
.add({ title });
} finally {
setPending(false);
}
};
return (
<div>
<input value={title} onChange={e => setTitle(e.target.value)} />
<button type="button" onClick={add}>
Add
</button>
{pending && "Pending..."}
</div>
);
};
エラー処理は省略しています。
Appコンポーネント
最後に、全体をつなげるAppコンポーネントとReactDOMのrenderです。
const App = () => {
return (
<div>
<TodoList />
<NewTodo />
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
CodeSandbox
https://codesandbox.io/s/wonderful-browser-zh0wc
完成したものがこちらです、実際に動作させるためにはforkしてfirebaseConfigを置き換える必要がありますのでご注意ください。
おわりに
Firestoreのリアルタイム更新とReact Hooksはとても相性がいいと感じました。ドキュメントを追加したら、すぐに更新されます。Firestoreのコンソールから追加しても同様です。
今回は、useCollectionDataを使いましたが、用意されているhooksはさらにあります。
- useCollection
- useCollectionOnce
- useCollectionData
- useCollectionDataOnce
- useDocument
- useDocumentOnce
- useDocumentData
- useDocumentDataOnce
Once系は一度だけの取得なのですが、その場合はhookがどれだけ役立つかは微妙です。callbackから使うことになることが多い気がします。また、Data系のhookはTypeScriptの型が付けられますが、ソースコード上は単にアサーションしているだけなので、予期せぬランタイムエラーが発生する可能性がありそうです。結局、独自の拡張をしようと思うとcustom hooksを作ることになりそうですが、その先に本ライブラリのhooksから合成できるかはやってみないと分からないといった感じになりそうです。