質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

0回答

865閲覧

Cloud Firestoreから投稿に紐づくコメント一覧(snapshot)を取得できない

moyong

総合スコア19

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/02/27 08:26

編集2022/01/12 10:55

前提・実現したいこと

Firebase, React Hooks, Redux TooklitでTwitterアプリのようなものを作っています。
(Twitterでいうリプライ的な)「コメント」を一覧表示する機能を実装したいです。

発生している問題

snapshotをとってくるところで

Firebase

1FirebaseError: Function CollectionReference.doc() cannot be called with an empty path.

というFirebaseのエラーが発生してしまいます。
イメージ説明

該当のソースコード

PostTsx

1// データベースから投稿に紐づくコメント一覧を取得してstateに入れる 2 useEffect(() => { 3 const unSub = db 4 .collection("training_posts") 5 .doc(props.postId) 6 .collection("comments") 7 .orderBy("timestamp", "desc") 8 .onSnapshot((snapshot) => { 9 setComments( 10 snapshot.docs.map((doc) => ({ 11 id: doc.id, 12 avatar: doc.data().avatar, 13 text: doc.data().text, 14 username: doc.data().username, 15 timestamp: doc.data().timestamp, 16 })) 17 ); 18 }); 19 return () => { 20 unSub(); 21 }; 22 }, [props.postId]);

Post.tsxへは、親のFeed.tsxからpropsを渡しています。

FeedTSX

1{posts.length && 2 <> 3 {posts.map((post) => ( 4 <Post 5 key={post.id} 6 postId={post.id} 7 avatar={post.avatar} 8 image={post.image} 9 trainingArray={post.trainingArray} 10 timestamp={post.timestamp} 11 username={post.username} 12 postUid={post.uid} 13 updateProfile={updateProfile} 14 /> 15 ))} 16 </> 17 }

FeedTSX

1// データベースから投稿一覧を取得してstateに入れる 2 useEffect(() => { 3 const unSub = db 4 .collection("training_posts") 5 .orderBy("timestamp", "desc") 6 .onSnapshot((snapshot) => setPosts( 7 snapshot.docs.map((doc) => ({ 8 id: doc.id, 9 avatar: doc.data().avatar, 10 image: doc.data().image, 11 trainingArray: doc.data().training_array, 12 timestamp: doc.data().timestamp, 13 username: doc.data().username, 14 uid: doc.data().uid 15 })) 16 )); 17 return () => { 18 unSub(); 19 }; 20 }, []);

Cloud Firestoreのコンソール画面

「training_posts」や「comments」という名前はないよ、とエラー文を解釈してコンソール画面を確認してみましたが、
タイプミスもないようですし、なぜアクセスできないのかが分からないです。
イメージ説明
イメージ説明

全体のソースコード

PostTSX

1import React, { useState, useEffect } from "react"; 2import styles from "./Post.module.css"; 3import { db } from "../firebase"; 4import firebase from "firebase/app"; 5import { useSelector } from "react-redux"; 6import { selectUser } from "../features/userSlice"; 7import { Avatar } from "@material-ui/core"; 8import { makeStyles } from "@material-ui/core/styles"; 9import MessageIcon from "@material-ui/icons/Message"; 10import SendIcon from "@material-ui/icons/Send"; 11import DeleteIcon from '@material-ui/icons/Delete'; 12interface PROPS { 13 postId: string; 14 avatar: string; 15 image: string; 16 trainingArray: any; 17 timestamp: any; 18 username: string; 19 postUid: string; 20 updateProfile: any; 21} 22interface COMMENT { 23 id: string; 24 avatar: string; 25 text: string; 26 timestamp: any; 27 username: string; 28} 29const useStyles = makeStyles((theme) => ({ 30 small: { 31 width: theme.spacing(3), 32 height: theme.spacing(3), 33 marginRight: theme.spacing(1), 34 } 35})) 36const Post: React.FC<PROPS> = (props) => { 37 const user = useSelector(selectUser); 38 const classes = useStyles(); 39 const [comment, setComment] = useState(""); 40 const [openComments, setOpenComments] = useState(false); 41 const [comments, setComments] = useState<COMMENT[]>([ 42 { 43 id: "", 44 avatar: "", 45 text: "", 46 username: "", 47 timestamp: null, 48 }, 49 ]); 50 const newComment = (e: React.FormEvent<HTMLFormElement>) => { 51 e.preventDefault(); 52 db.collection("training_posts").doc(props.postId).collection("comments").add({ 53 avatar: user.photoUrl, 54 text: comment, 55 timestamp: firebase.firestore.FieldValue.serverTimestamp(), 56 username: user.displayName, 57 }); 58 setComment(""); 59 } 60 // 投稿削除 61 const deletePost = () => { 62 if (user.uid === props.postUid) { 63 db.collection("training_posts").doc(props.postId).delete(); 64 } else { 65 console.log("failed to delete!") 66 } 67 }; 68 // データベースから投稿に紐づくコメント一覧を取得してstateに入れる 69 useEffect(() => { 70 const unSub = db 71 .collection("training_posts") 72 .doc(props.postId) 73 .collection("comments") 74 .orderBy("timestamp", "desc") 75 .onSnapshot((snapshot) => { 76 setComments( 77 snapshot.docs.map((doc) => ({ 78 id: doc.id, 79 avatar: doc.data().avatar, 80 text: doc.data().text, 81 username: doc.data().username, 82 timestamp: doc.data().timestamp, 83 })) 84 ); 85 }); 86 return () => { 87 unSub(); 88 }; 89 }, [props.postId]); 90 return ( 91 . 92 . 93 . 94 ) 95} 96export default Post 97

FeedTSX

1import React, { useState, useEffect } from 'react' 2import styles from './Feed.module.css'; 3import { db } from "../firebase"; 4import TrainingInput from './TrainingInput'; 5import Post from './Post'; 6import User from './User'; 7import { selectUser } from "../features/userSlice"; 8import { useSelector } from "react-redux"; 9interface User { 10 profileUserName: string; 11 avatar: string; 12} 13interface Post { 14 id: string; 15 avatar: string; 16 image: string; 17 trainingArray: []; 18 timestamp: any; 19 username: string; 20 uid: string; 21} 22const Feed: React.FC = () => { 23 const [ posts, setPosts] = useState<Post[]>([{ 24 id: "", 25 avatar: "", 26 image: "", 27 trainingArray: [], 28 timestamp: null, 29 username: "", 30 uid: "", 31 }, 32 ]); 33 const user = useSelector(selectUser); 34 const [profileUser, setProfileUser ] = useState<User>({ 35 profileUserName: user.displayName, 36 avatar: user.photoUrl 37 } 38 ) 39 // データベースから投稿一覧を取得してstateに入れる 40 useEffect(() => { 41 const unSub = db 42 .collection("training_posts") 43 .orderBy("timestamp", "desc") 44 .onSnapshot((snapshot) => setPosts( 45 snapshot.docs.map((doc) => ({ 46 id: doc.id, 47 avatar: doc.data().avatar, 48 image: doc.data().image, 49 trainingArray: doc.data().training_array, 50 timestamp: doc.data().timestamp, 51 username: doc.data().username, 52 uid: doc.data().uid 53 })) 54 )); 55 return () => { 56 unSub(); 57 }; 58 }, []); 59 //ユーザープロフィール画面の表示をユーザーごとに切り替える 60 const updateProfile = (name:string, avatar:string) => { 61 console.log(`${name} + ${avatar}`); 62 setProfileUser({ 63 profileUserName: name, 64 avatar: avatar, 65 }) 66 } 67 return ( 68 . 69 . 70 . 71 ); 72} 73export default Feed 74

原因がわかりましたら、教えていただきたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/02/27 08:53

props.postId に "" (空文字列) が渡されてるのでは。このコンポーネントはどうやって使ってますか? comments の初期値に値が空のオブジェクトを設定する意味もよくわからないし…。
moyong

2021/02/27 11:53

hoshi-takanoriさん、ありがとうございます。 帰宅次第props.postIdを出力してデバッグしてみます。コンポーネントの用途も本文に追加させていただきます。
hoshi-takanori

2021/02/27 12:09

Feed.tsx の posts の初期値がどうなってるかが問題ですね。空配列 [] なら問題ないはずですが、Post の comments のように const [posts, setPosts] = useState<POST[]>([ { id: "", ... }, ]); と id が空文字列 "" のオブジェクトを設定していたら Post が postId="" で呼ばれることになります。
moyong

2021/02/27 14:26

おかげさまで、解決しました! commentsもpostsも、値が空のオブジェクトをsetStateの初期値に設定してしまっていました。 今回の場合、setStateの初期値としては「stateが配列であること」を示しさえすればよくて、その中のオブジェクトがどのようなキーをもっているかまでは書かなくてよかったのですね...! 今回も助けていただいて本当にありがとうございますm(__)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問