前提・実現したいこと
ReactとFirebaseを使い、ユーザーがテキストを投稿するアプリを作成しています。
下記はデモです。
demo(CodeSandBox)
※CodeSandBox
でFirebaseの諸機能を動かす方法が分からなかったため、上記のデモは全く機能しないもののFirebaseで使うメソッドを書いています。
実現したい流れは下記の通りです。
- Appコンポーネントがレンダーされたら、投稿データをデータベースから取得する
- Postデータに含まれるユーザー名から、ユーザーデータをデータベースから取得する
- 投稿データにユーザーデータを添えて、
array.map()
でレンダーする
投稿データのユーザー名はnull
を許容します。
イメージとしては、アカウントを持っていなくても投稿できて、アカウントを持っている人がいたらユーザー名を添える、という感じです。
発生している問題・エラーメッセージ
Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
エラーをググっても意味は理解できなかったのですが、コンポーネントのトップレベルでasync/await
を使うことはできないとは、なんとなく肌感覚ですが理解しておりまして、これがエラーの原因であると認識しています。
該当のソースコード
js
1const App = async () => { 2 const postsCollection = await db.collection("posts").get(); 3 const posts = postsCollection.data(); 4 5 const renderPosts = posts.map(async (item, index) => { 6 const userDocument = await db 7 .collection("users") 8 .doc(item.user) 9 .get(); 10 const user = userDocument.data(); 11 const name = user.name; 12 const address = user.address; 13 14 return ( 15 <li key={index} style={{ marginBottom: "50px" }}> 16 <p>投稿: {item.post}</p> 17 <p>名前: {name}</p> 18 <p>住所: {address}</p> 19 </li> 20 ); 21 }); 22 23 return ( 24 <> 25 <ul>{renderPosts}</ul> 26 </> 27 ); 28};
試したこと
ライブラリによってトップレベルでasync/await
を使うことなく投稿データを取得できました。
js
1const App = () => { 2 const posts = useCollectionData(db.collection("posts"))[0]; 3 console.log(posts) // [PostA, PostB, PostC] 4 ...
同じライブラリに、コレクションではなくドキュメントのデータを取得するHooksもありました。
js
1const user = useDocumentData(db.doc("UserA"))[0];
doc
メソッドにはドキュメント名を渡す必要がありますが、ドキュメント名は投稿データに含まれるユーザー名を渡したいため、array.map()
内で実行する必要があるかと思います。
しかし、コンポーネントのトップレベルではないためライブラリのHooksが使えない、という状態です。
そのほか、ユーザーのデータをuseState()
利用し、array.map()
のreturn()
に含まれるユーザーの名前と住所に渡してみました。
結果、投稿にユーザー情報を添えることができたのですが、動きがもっさりしていたのでarray.map()
内でconsole.log()
を記述してレンダーされた回数を確認したろ、物凄い数のレンダーが実行されていました。
そのため、パフォーマンス性を著しく損なう実装方法は避けたいです。
ライブラリを使用することにこだわりは無いです。
現状のコンポーネントのトップレベルではライブラリのHooksを使って、array.map()
内では使わない、というのは綺麗ではないと思います。
ただ現状は、コードの綺麗さよりも機能を実装することを優先しています。
あなたの回答
tips
プレビュー