ユーザーアイコン

mizuko

3か月前

0
0

react-infinite-scrollerで無限ロードを実現する

Next.js
react-infinite-scroller

特筆事項は特にないが、hasMoreのハンドリングをしっかりしていないと、データ取得後にずっとロード中のUIが表示されてしまうため注意

export const MemoContainer = (): JSX.Element => { const [memos, setMemos] = useState<Memo[]>([]); const [memoPage, setMemoPage] = useState(1); const [memoHasMore, setMemoHasMore] = useState(true); const { data: memosData, isLoading, isError, } = useGetMeMemoLikes({ page: memoPage }); useEffect(() => { if (memosData && memosData.memos.length === 0) { setMemoHasMore(false); } }, [memosData]); if (isError) { errorToast('メモの取得に失敗しました。'); } if (isLoading) { return <LinearLoading />; } return ( <InfiniteScroll pageStart={0} loadMore={() => { refetchData<Memo>( memosData?.memos, memosData?.total, memoPage, setMemos, setMemoPage, setMemoHasMore ); }} initialLoad={true} hasMore={memoHasMore} loader={<SimpleSpinner className='mt-8' key='memo-loader' />} > <MemoList memos={memos} /> </InfiniteScroll> ); };
export const refetchData = <T>( newData: T[] | undefined, total: number | undefined, page: number, setData: React.Dispatch<React.SetStateAction<T[]>>, setPage: React.Dispatch<React.SetStateAction<number>>, setHasMore: React.Dispatch<React.SetStateAction<boolean>> ): void => { if (!page || !newData || !total) return; if (newData.length === 0) { setHasMore(false); return; } setData((prevData) => { // 重複データを除外 const filteredNewData = newData.filter( (newItem) => !prevData.some((prevItem) => equals(prevItem, newItem)) ); const mergedData = [...prevData, ...filteredNewData]; if (mergedData.length >= total) { setHasMore(false); } else { setPage(page + 1); } return mergedData; }); };