#はじめに
Reactでチャットアプリを作成する際に無限スクロール欲しいよなあと思い作成したので記録しておく。
#仕様
https://github.com/danbovey/react-infinite-scroller
使用するコンポーネントはInfiniteSchrollerのみ。スクロールイベントで発火する仕組みのよう。主にpropsとして使用するものを紹介する。
###loadmore
ロードする際に実行する関数。
###hasMore
loadMoreを実行するかどうかを判断するboolean。のはずなのだが、falseにしてもloadmoreが一回だけ動いたりした。要検証。
###initialLoad
初回にロードするかどうかを決めるboolean。初回時と読み込み時で処理が違う場合はfalseにした方が良さそう。
###loader
ローディング中のUI。
###threshold
スクロールイベントを検知するためのスクロールバーとウィンドウ下の距離。大きくしたり小さくしたりするとエラーが出ることがあるのでテスト必須。
#コード
export const FirebaseChatDisplayArea = () => {
const { chatData } = useChatDataSelector();
const { hasMore } = useHasMoreSelector();
const { isChatsCompleted } = useIsChatsCompletedSelector();
const { lastChatOrder } = useLastChatOrderSelector();
const { dispatch } = useAppDispatch();
//初回時のみ実行、それ以降はDBに変更があった時のみ動作
useFetchData();
console.log("チャット表示領域のレンダリング");
return (
<SChatListContainer>
{isChatsCompleted ? (
<InfiniteScroll
loadMore={() =>
loadMore({
dispatch,
chatData,
lastChatOrder,
hasMore,
})
}
hasMore={hasMore}
loader={<CircularProgress key={0} />}
initialLoad={false}
threshold={50}
>
{chatData.length === 0 ? (
<div>チャットはありません</div>
) : (
chatData.map((item) => {
return (
<SChatContainer key={item.key}>
<SContent>{item.user_name}</SContent>
<SContent>{item.text}</SContent>
<SContent>{moment(item.createdAt).fromNow()}</SContent>
<SContent>{item.order}</SContent>
</SChatContainer>
);
})
)}
</InfiniteScroll>
) : (
<CircularProgress />
)}
</SChatListContainer>
);
};
特に変わったところはないと思います。
#遭遇したエラーと対策
###keyを設定しろと言われる
公式のコードや、issueにも載っているが、loaderにkey={0}
としないと怒られる。
###同じデータを読んでしまい、同じkeyが存在すると言われる
thresholdの値が大きすぎるとloadmoreの実行中にもう一度イベントが発生し、同じデータを読んでしまうことがある。このエラーはロジック上の問題であるときもあるので十分な分析が必要。
#おわりに
意外とめんどくさかった。みんな手動で実装してるんだろうか。