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

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

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

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

Router

Routerは、異なるネットワーク同士を相互に接続するための通信機器。インターネットでのデータを自動的に振り分け、一つのインターネット回線を複数のコンピュータで使用することが可能です。DHCPによりIPアドレスを自動的に割振りすることもできます。

React.js

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

Q&A

解決済

1回答

709閲覧

reactでURLパラメーターを使うfirebaseのデータ取得で、再リロードやURL直打ちすると取得できない

SOTETU

総合スコア1

Firebase

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

Router

Routerは、異なるネットワーク同士を相互に接続するための通信機器。インターネットでのデータを自動的に振り分け、一つのインターネット回線を複数のコンピュータで使用することが可能です。DHCPによりIPアドレスを自動的に割振りすることもできます。

React.js

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

0グッド

0クリップ

投稿2023/04/30 00:33

実現したいこと

URLパラメーターを使ったfirebaseからのデータの取得

(自分なりに土曜日を費やしたのですが解決しませんでした。協力お願いします)

前提

現在練習としてTwitterクローンを作っていて、
React, ChakraUI, Javascript, react-router v6と、データベースにfirebaseを使っています

その過程の、プロフィール画面を作る段階で詰まってしまいました

下記のようなRouterの設定で、常にレフトバーとライトバーは表示させつつ
真ん中の部分をタイムライン画面やプロフィール画面にする設計にしています。
そして、プロフィール画面に飛んだ時に、そのURLパラメーターによってどのユーザーのプロフィールを表示させるのか識別させています

javascript

1function AppRoutes() { 2 return ( 3 <> 4 <Flex justify="center"> 5 <LeftSidebar /> 6 <Routes> 7 <Route path="/" element={<Timeline />} /> 8 <Route path="/profile/:userId/*" element={<Profile />} /> 9 <Route path="*" element={<NotFound />} /> 10 </Routes> 11 <RightSidebar /> 12 </Flex> 13 </> 14 ); 15} 16export default AppRoutes;

そしてApp.jsで、ちゃんと挟んでいます

javascript

1 <BrowserRouter> 2 <UserProvider> 3 <ChakraProvider theme={CustomTheme}> 4 <AppRoutes /> 5 </ChakraProvider> 6 </UserProvider> 7 </BrowserRouter>

そして、実際の取得について

まずfirebaseの構造としては
postsコレクションにそれぞれの投稿をドキュメントをして格納しています
usersコレクションの中にそれぞれのユーザーをドキュメントとして格納し
(そしてそれぞれのユーザードキュメントに一意のuserIdフィールドを設けています)

ーーーーーーーーーーーーーーーーーーーー

そして動作の流れとしては
①URLパラメーターの値を取得し、userIdフィールドにそのURLパラメーターの値を持っているアカウントのドキュメントを、usersコレクションから探す

②そのアカウントの情報が入ったオブジェクトを取得し、useStateでsetし、それを画面の「アイコン」とか「アカウント名」とか…の情報として表示させる

==

③次に「手順②」URLパラメーターの値を持っている投稿のドキュメントをpostsから探して取得する(つまり、URLパラメーターのuserIdのアカウントが投稿した投稿)

④それをデータとして解析して、useStateでposts配列にsetする

⑤map関数で出力する

<動作の目的>
・①②がプロフィールでアカウントの基本情報を表示
・③④⑤が、そのアカウントからされた投稿だけを取得して表示

ーーーーーーーーーーーーーーーーーーーー

発生している問題・エラーメッセージ

という流れになっていて
①、②の取得と表示は全く問題ありません。
ですが、③④に問題があるのです

現在react-routerのnavigateを使ってプロフィールに遷移するようにしていて、その手順で遷移した時はしっかりと「手順④」でposts配列にデータが格納されて投稿が出力されるのですが、その状態で再リロード(再読み込み)すると投稿が表示されなくなってしまうのです

コンソールを見ると、posts配列が空でした。つまりでデータが取得できていないのです

navigateから遷移するとちゃんと取得して表示されるのに…
再リロード(再読み込み)やURL直打ちすると取得できずにposts配列が空で、投稿が表示されません

該当のソースコード(Profile.jsxの全文)

javascript

1import { 2 Avatar, 3 Box, 4 Button, 5 Flex, 6 HStack, 7 Icon, 8 Image, 9 Text, 10 VStack, 11} from '@chakra-ui/react'; 12import React, { useEffect, useState } from 'react'; 13import { useNavigate, useParams } from 'react-router-dom'; 14import { 15 collection, 16 query, 17 where, 18 getDocs, 19 orderBy, 20 onSnapshot, 21} from 'firebase/firestore'; 22import { db } from '../../../firebase'; 23import HeaderCenter from '../Molecules/HeaderCenter'; 24import { AiOutlineArrowLeft, AiOutlineLink } from 'react-icons/ai'; 25import Post from '../Organisms/Post'; 26 27function Profile() { 28 const navigate = useNavigate(); 29 const [userData, setUserData] = useState(); 30 const [isLoading, setIsLoading] = useState(false); 31 const [posts, setPosts] = useState([]); 32 const { userId } = useParams(); 33 34 const getUserByUserId = async _userId => { 35 const q = query(collection(db, 'users'), where('userId', '==', _userId)); 36 const querySnapshot = await getDocs(q); 37 const userDocs = querySnapshot.docs[0].data(); 38 return userDocs; 39 }; 40 41 useEffect(() => { 42 setIsLoading(true); 43 getUserByUserId(userId) 44 .then(userDocs => { 45 setUserData(userDocs); 46 }) 47 .then(() => { 48 setIsLoading(false); 49 }); 50 51 const postsRef = collection(db, 'posts'); 52 console.log(userId); 53 const postsQ = query( 54 postsRef, 55 where('userId', '==', userId), 56 orderBy('time', 'desc') 57 ); 58 console.log(postsQ); 59 const unsubscribe = onSnapshot(postsQ, querySnapshot => { 60 setPosts( 61 querySnapshot.docs.map(doc => ({ docId: doc.id, ...doc.data() })) 62 ); 63 }); 64 65 return () => { 66 unsubscribe(); 67 }; 68 }, [userId]); 69 70 return ( 71 <> 72 <Box 73 w={{ base: '100%', sm: '42rem' }} 74 spacing="0" 75 h="100vh" 76 borderRight="1.5px solid #e4e4e4" 77 borderLeft="1.5px solid #e4e4e4" 78 position="relative" 79 overflowY="scroll" 80 sx={{ 81 '&::-webkit-scrollbar': { 82 display: 'none', 83 }, 84 '-ms-overflow-style': 'none', 85 'scrollbar-width': 'none', 86 }} 87 > 88 <HeaderCenter> 89 <HStack> 90 <Button 91 variant="secondary" 92 size="9" 93 sx={{ 94 w: '10', 95 h: '10', 96 ml: '2', 97 }} 98 onClick={() => { 99 navigate('/'); 100 }} 101 > 102 <Icon as={AiOutlineArrowLeft} boxSize="6" /> 103 </Button> 104 <Text variant="title"> 105 {!isLoading ? userData?.displayName : '..........'} 106 </Text> 107 </HStack> 108 </HeaderCenter> 109 <Image 110 src={userData?.headerImage} 111 fallbackSrc={'https://colorate.azurewebsites.net/SwatchColor/D3D3D3'} 112 sx={{ 113 w: '100%', 114 h: '40', 115 bg: 'subGray.400', 116 objectFit: 'cover', 117 objectPosition: 'center', 118 }} 119 /> 120 <Avatar 121 src={userData?.photoURL} 122 sx={{ 123 boxSize: '40', 124 position: 'absolute', 125 top: '32', 126 left: '6', 127 border: '5px solid white', 128 imageRendering: 'optimizeQuality', 129 }} 130 /> 131 <VStack 132 align="start" 133 mt="6.2rem" 134 pl="4" 135 pb="3" 136 spacing="1" 137 borderBottom="1.5px solid #e4e4e4" 138 > 139 <Text variant="title" fontSize="2xl"> 140 {userData?.displayName} 141 </Text> 142 <Text variant="subTitle" fontSize="lg"> 143 @{userData?.userId} 144 </Text> 145 {userData?.webSite ? ( 146 <Flex align="center" color="blue.500" fontSize="md" pt="3"> 147 <Icon as={AiOutlineLink} /> 148 <a href={userData.webSite}>{userData.webSite}</a> 149 </Flex> 150 ) : ( 151 <Flex 152 align="center" 153 fontSize="md" 154 pt="3" 155 color="blue.500" 156 cursor="default" 157 > 158 <Icon as={AiOutlineLink} /> 159 <Text variant="subTitle" color="blue.500"> 160 Webサイトは設定されていません 161 </Text> 162 </Flex> 163 )} 164 <HStack spacing="6" pt="5"> 165 <Text variant="subTitle">{userData?.following || 0}フォロー中</Text> 166 <Text variant="subTitle">{userData?.folower || 0}フォロワー</Text> 167 </HStack> 168 </VStack> 169 {posts?.map(postData => ( 170 <Post postData={postData} /> 171 ))} 172 </Box> 173 </> 174 ); 175} 176 177export default Profile;

試したこと

PCの再起動
サーバーの再起動
chatGPTに聞いてみる
コードを自分なりに弄ってみる
react-routerのバージョン確認

補足情報(FW/ツールのバージョンなど)

npmを使っています

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

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

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

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

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

hoshi-takanori

2023/04/30 05:41

とりあえず getUserByUserId や onSnapshot でエラーが起きてないか確認してみては。
guest

回答1

0

自己解決

コメントありがとうございます
アドバイスを受けて再度コンソールをよく見てみた所問題に気付きました

コンソールのエラーとしてfirebaseで複合インデックスの作成を求められていました
なのでエラーメッセージに表示されているURLに飛び、指示に従ってfirebase側で作成することで解決しました

コメントをくださった方、閲覧してくださった方々、ありがとうございました

投稿2023/04/30 12:24

SOTETU

総合スコア1

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問