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

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

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

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

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

Q&A

0回答

846閲覧

firebase React データをリッスンしながらページネーション

Patao150205

総合スコア10

Firebase

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

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

0グッド

0クリップ

投稿2021/05/16 04:10

編集2021/05/16 04:52

前提・実現したいこと

SNSをつくっています。使用技術は、firebaseとReactです。
firebaseのonSnapshotを使用してリアルタイムに更新したいです。

具体的には、今現在表示しているページだけをリッスンして、ページを左右のボタンで切り替えるたびにリッスンの対象を切り替えて投稿を表示することを実現したいです!

今、実装しようと試みてますが大苦戦中です。うまく動いてくれません。
ソースコードにコメントで実装の説明を書いてます。
見てもらえば、考え方などわかっていただけると思いますが、どのように改善すればいいでしょうか?

onSnapshotを使うにはUseEffectを使用すると思いますが、useEffectの制御にも苦戦しています。

該当のソースコード

TypeScript

1 2const Record = () => { 3 const user = auth.currentUser; 4 const dispatch = useAppDispatch(); 5 const selector = useSelector(userRecordSelector); 6 const classes = useStyles(); 7 //表示している投稿の最初と最後のレコードを保持 8 const [currentFirstRecord, setCurrentFirstRecord] = useState<any>(null); 9 const [currentLastRecord, setCurrentLastRecord] = useState<any>(null); 10 //全投稿の一番最初と最後のレコードを保持 11 const [firstRecord, setFirstRecord] = useState<any>(); 12 const [lastRecord, setLastRecord] = useState<any>(); 13 //前後のページが存在するか否か 14 const [isPrevPage, setIsPrevPage] = useState(true); 15 const [isNextPage, setIsNextPage] = useState(true); 16 //スナップショットのクエリの切り替え用のステート 17 const [direction, setDirection] = useState<"initial" | "left" | "right">("initial"); 18 19 useEffect(() => { 20 //全投稿の最初の投稿を監視 21 const unsubFirst = db 22 .collection("users") 23 .doc(user?.uid) 24 .collection("userRecords") 25 .orderBy("created_at", "desc") 26 .limit(1) 27 .onSnapshot((snapshot) => { 28 setFirstRecord(snapshot.docs[0].data()); 29 }); 30 //全投稿の最後の投稿を監視 31 const unsubLast = db 32 .collection("users") 33 .doc(user?.uid) 34 .collection("userRecords") 35 .orderBy("created_at") 36 .limit(1) 37 .onSnapshot((snapshot) => { 38 setLastRecord(snapshot.docs[0].data()); 39 }); 40 41 return () => { 42 unsubFirst(); 43 unsubLast(); 44 }; 45 }, [user]); 46 47 useEffect(() => { 48 if (user) { 49 const limitCount = 3; 50 let query: any; 51 console.log(direction); 52 console.log("現在のラスト", currentLastRecord); 53 //directionの値に応じたクエリを生成 54 switch (direction) { 55 //初期の読み込み 56 case "initial": 57 query = db.collection("users").doc(user.uid).collection("userRecords").orderBy("created_at", "desc"); 58 break; 59 //前のページヘの遷移時のクエリ 60 case "left": 61 query = db 62 .collection("users") 63 .doc(user.uid) 64 .collection("userRecords") 65 .orderBy("created_at") 66 .startAfter(currentFirstRecord); 67 break; 68 //後のページヘの遷移時のクエリ 69 case "right": 70 query = db 71 .collection("users") 72 .doc(user.uid) 73 .collection("userRecords") 74 .orderBy("created_at", "desc") 75 .startAfter(currentLastRecord); 76 break; 77 } 78 console.log(query); 79 const unsubscribe = query.limit(limitCount).onSnapshot((snapshot: any) => { 80 const postsData: UserRecord[] = []; 81 snapshot.forEach((doc: any) => { 82 let data = doc.data() as UserRecord; 83 console.log(data); 84 //Date型にキャスト 85 if (data.created_at.seconds) { 86 data.created_at = data.created_at.toDate().toLocaleString(); 87 data.updated_at = data.updated_at.toDate().toLocaleString(); 88 } 89 if (data.othersComments?.comments) { 90 data.othersComments.comments.map((comment) => { 91 if (comment.created_at.seconds) { 92 comment.created_at = comment.created_at.toDate().toLocaleString(); 93 } 94 }); 95 } 96 postsData.push(data); 97 }); 98 dispatch(reflectRecordData(postsData)); 99 //現在表示している投稿の前後を保持する。 100 setCurrentFirstRecord(postsData[0]); 101 setCurrentLastRecord(postsData[postsData.length - 1]); 102 //現在表示している投稿に、全投稿の一番初めと最後の投稿が含まれているかを判断して、含まれている場合falseに、これを元に左右のボタンの有効無効を切り替える。 103 if (postsData && firstRecord) { 104 if (postsData.length > 0) { 105 postsData.forEach((item: UserRecord) => { 106 console.log("こっち"); 107 if (item.recordId === firstRecord.recordId) { 108 setIsPrevPage(false); 109 return; 110 } 111 }); 112 setIsPrevPage(true); 113 } 114 } 115 if (postsData && lastRecord) { 116 if (postsData.length > 0) { 117 postsData.forEach((item: UserRecord) => { 118 if (item.recordId === lastRecord.recordId) { 119 setIsNextPage(false); 120 return; 121 } 122 }); 123 setIsNextPage(true); 124 } 125 } 126 }); 127 return () => { 128 unsubscribe(); 129 }; 130 } 131 }, [user, direction, firstRecord, lastRecord]); 132 133 console.log(firstRecord); 134 console.log(lastRecord); 135 console.log(currentFirstRecord); 136 console.log(currentLastRecord); 137 console.log(isNextPage); 138 console.log(isPrevPage); 139 140 const handleNext = () => { 141 setDirection("right"); 142 }; 143 const handlePrev = () => { 144 setDirection("left"); 145 }; 146} 147 148//以下はあまり関係のない実装です。 149 150const handleDelete = useCallback( 151 (uid: string, recordId: string) => { 152 const isPost = confirm("本当に投稿を削除してよろしいでしょうか?"); 153 if (isPost) { 154 const newPosts = selector.filter((ele: UserRecord) => ele.recordId !== recordId); 155 const query = { 156 uid, 157 recordId, 158 newPosts, 159 }; 160 dispatch(deleteUserRecord(query)); 161 } 162 }, 163 [selector] 164 ); 165 166 return ( 167 <> 168 <Head> 169 <title>STUDIOUS 学習記録</title> 170 </Head> 171 {selector?.length !== 0 ? ( 172 <> 173 <section className={`c-section-wrapping--main`}> 174 {selector?.map((post) => ( 175 <PostCard handleDelete={handleDelete} key={post.recordId} post={post} /> 176 ))} 177 <IconButton onClick={handlePrev}> 178 <FontAwesomeIcon icon={["fas", "chevron-left"]} /> 179 </IconButton> 180 <IconButton onClick={handleNext}> 181 <FontAwesomeIcon icon={["fas", "chevron-right"]} /> 182 </IconButton> 183 </section> 184 </> 185 ) : ( 186 <div className={`${classes.noPostRoot} c-section-container`}> 187 <h1>投稿がありません。作成してみよう!</h1> 188 <div className="module-spacer--medium" /> 189 <Link href="/record/edit"> 190 <a>投稿作成ページへ</a> 191 </Link> 192 </div> 193 )} 194 </> 195 );

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問