無限スクロールの実装
前回SWRを導入したが、件数が少ないうちは良いのだが、件数が増えてくるとロード時間が長くなる問題が発生する。
という訳で今回はページングを実装したい。
SWR公式をよく読んでみるとページングはサポートされているようで、
useSWRではなくuseSWRInfiniteを使用すれば良さそう。
react-infinite-scrollerコンポーネントを利用すれば無限スクロールを簡単に実装できるようだ。
という訳で今回はページングを実装したい。
SWR公式をよく読んでみるとページングはサポートされているようで、
useSWRではなくuseSWRInfiniteを使用すれば良さそう。
react-infinite-scrollerコンポーネントを利用すれば無限スクロールを簡単に実装できるようだ。
npm install swr --save
npm install react-infinite-scroller --save
BlogPostsList.tsx
useSWRInfinitはページの配列で返ってくるので、 initialDataはページの配列で渡してやるのがハマりどころだった。
import firebase from 'firebase'
import flamelink from 'flamelink/app'
import 'flamelink/content'
import { useSWRInfinite } from "swr";
import InfiniteScroll from "react-infinite-scroller"
export default function BlogPostsList(props: any) {
const textLength = 100;
const getPostFunc: any = (url: any, lastPost: any) => {
return getPosts(lastPost)
};
const { data, error, size, setSize } = useSWRInfinite(
(index, previousPageData) => {
let lastPage = undefined;
if (previousPageData && previousPageData.length > 0) {
lastPage = previousPageData[previousPageData.length - 1];
}
return [props.key + '/' + (index + 1), lastPage];
},
getPostFunc,
{ initialData: [props.initialData] } //初期データ。配列で渡す
);
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
const postData = data ? [].concat(...data) : [];
const isLoadingInitialData = !data && !error;
const isLoadingMore =
isLoadingInitialData ||
(size > 0 && data && typeof data[size - 1] === "undefined");
const isEmpty = data?.[0]?.length === 0;
const isReachingEnd =
isEmpty || (data && data[data.length - 1]?.length < props.pageSize);
const loadMore = () => {
if (!isLoadingMore && !isReachingEnd) {
setSize(size + 1);
}
};
return (
<InfiniteScroll
loadMore={loadMore} //項目を読み込む際に処理するコールバック関数
hasMore={!isReachingEnd} //読み込みを行うかどうかの判定*/}
loader={<>loading...</>}> {/* 読み込み最中に表示する項目 */}
{postData.map(post => <div>{post.title}</div>)} {/* 無限スクロールで表示する項目 */}
</InfiniteScroll>
)
}
export const getStaticProps: GetStaticProps = async () => {
const posts = await getPosts();
return {
props: {
posts: posts
}
}
}
const getPosts: any = async (lastPost?: any) => {
const getOptions: any = { schemaKey: "myposts", populate: true, filters: [['_fl_meta_.status', '==', 'publish']], orderBy: [{ field: 'like', order: 'desc' }, 'id'], limit: PAGE_PER_CONTENTS };
if (lastPost && lastPost.like !== undefined && lastPost.id !== undefined) {
getOptions.startAfter = [lastPost.like, lastPost.id];
}
const _posts = await app.content.get(getOptions);
const posts: any[] = [];
if (_posts) {
Object.keys(_posts).forEach(key => {
const post = _posts[key]
delete (post._fl_meta_);
posts.push(post)
});
}
return posts;
}
const PAGE_PER_CONTENTS = 10
const firebaseApp = firebase;
const app = flamelink({
firebaseApp,
dbType: "cf",
});
react-infinite-scroller公式
https://github.com/danbovey/react-infinite-scroller#readme
https://github.com/danbovey/react-infinite-scroller#readme