実現したいこと
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を使っています

回答1件
あなたの回答
tips
プレビュー