React Native ExpoでFirestore+unstatedを使って更新機能を作る

2 min読了の目安(約2100字TECH技術記事

前提としてデータの追加・削除・更新はreferenceに対して行います。

そのため、更新する際はまずドキュメントIDからdocumentReferenceを取得する必要があります。

扱うデータモデルを確認

以下のような投稿データを管理するデータモデルを想定しています。
idはFirestoreのドキュメントIDが入っています。

export type Post = {
  id: string,
  name: string,
  description: string,
  photo: string,
  likeCount: number,
}

Firebaseの共通クラスにupdate処理を実装する

React Native ExpoでFirebaseを使う場合は処理をまとめておくと便利です。
ここではutils/Fire.tsという共通ファイルを追加しています。

documentReferenceに対してupdateする

前提としてFirestoreでデータを追加・削除・更新する場合は、Referenceに対して行います。

そのためpostsコレクションから一度ドキュメントIDでdocumentReferenceを取得してから、
受け取ったデータで更新を行っています。

//utils/Fire.ts

updatePost = async (post: Post) => {
  const postDocumentReference = this.db.collection('posts').doc(post.id)
  await postDocumentReference.update({
    name: post.name,
    description: post.description,
    photo: post.photo,
    likeCount: post.likeCount,
  })
}

非同期処理はunstatedのContainer内に書く

unstatedのContainerとは、
Reduxでいう所の「Action+Reducer+Middleware+Store」みたいなイメージです。

管理している対象のグローバルなstateに対する取得や変更の処理を、
全て一箇所にできるのでReduxに比べるとスッキリと書くことが出来ます。

unstatedのContainer内に実装する例

Container内でまずFirestoreの更新処理を実行してから、stateを更新するようにします。
本来はFirebase側のエラーハンドリングが必要ですが、ここでは省いています。

updatePost = async (post: Post) => {
  const {
    posts
  } = this.state

  // Firebase更新処理
  await Fire.shared.updatePost(post)

  let newPosts: Array<Post> = [...posts]
  let newPost: Post = newPosts[postIndex]
  newPost.name = post.name
  newPost.description = post.description
  newPost.photo = post.photo
  newPosts[postIndex] = newPost

  this.setState({ posts: newPosts })
}

React Native Debuggerでデバッグする

上手く更新ができない場合はReact Native Debuggerのログを見ましょう。

自分の場合は最初動かなったのですが、ビュー側でlikeCountを渡すのを忘れていたため、
undefinedの値が弾かれていたのが原因でした。

おわりに

今日書いたコードはGithubに上げているので、全文を見たい方は参考にしてみてください。
もしよければスターもつけていただけると嬉しいです。

https://github.com/masarufuruya/100days-challenge-react-native

参考にした資料

https://www.wakuwakubank.com/posts/723-firebase-firestore-query/
https://qiita.com/ryokkkke/items/d3a0375ef51448d345ed