【React・GraphQL】無限スクロールを実装する!
上を参考にしました。
インストール
npm install react-infinite-scroller --save
使用するファイルでimport文を加えます
import InfiniteScroll from 'react-infinite-scroller';
API実装
APIはlaravel lighthouseで実装します。自分は前回の記事をちょっとだけ改造しているだけです。
My APIを持っておくと勉強の時に便利です!
無限スクロールを実装するために行なったのはたったこれだけで、paginateディレクティブを追加しただけです。
type Query {
#ツイートを全て取得
tweets: [Tweet!]! @paginate
}
ドキュメントによるとpaginateディレクティブを使うだけで、上記のクエリ定義が"以下のように定義された"と解釈できるようになります。
type Query {
tweets(first: Int!, page: Int): TweetPaginator
}
type TweetPaginator {
data: [Tweet!]!
paginatorInfo: PaginatorInfo!
}
dataフィールドには取得したTweet情報、そしてpaginatorInfoにはページネーションに関する情報が格納されています。以下の画像を見て貰えばわかるように、どのような情報が入っているのか想像できます。今回はhasMorePagesを使って、取得できるTweetがあるかないかを判断しました。
tweets(first:3,page:1)とすることで、1ページ目として全体のデータから3件のTweetを取得できるようになります。今回はfirstの値を固定し、pageを可変にすることでスクロールのたびにクエリを投げ3件づつTweetを取得するということをしていきたいと思います。
無限スクロールを実装
import { useLazyQuery, useQuery } from "@apollo/client";
import React, { useState } from "react";
import InfiniteScroll from "react-infinite-scroller";
import { FETCH_TWEET } from "./gql/paginate";
import { useApolloClient } from "@apollo/client";
function App() {
const [tweetList, setTweetList] = useState<any>([]);
const [hasMore, sethasMore] = useState(true);
const client = useApolloClient();
const loadMore = async (page: number) => {
const data = await client.query({
query: FETCH_TWEET,
variables: { page },
});
sethasMore(data.data.tweets.paginatorInfo.hasMorePages);
setTweetList([...tweetList, ...data.data.tweets.data]);
console.log(page);
console.log(tweetList);
};
const items = (
<ul>
{tweetList.map((val: { content: string }) => {
return <li>{val.content}</li>;
})}
</ul>
);
return (
<div style={{ height: "500px", overflow: "auto" }}>
<InfiniteScroll
loadMore={loadMore}
hasMore={hasMore}
loader={<div>Tweetロード中...</div>}
useWindow={false}
>
{items}
</InfiniteScroll>
</div>
);
}
export default App;
無限スクロールを実装するにはInfiniteScrollタグで、ロードしたいアイテムを囲い、必要とされているPropsを指定してあげる必要があります。
Propsに関して詳しくはこちら(https://github.com/danbovey/react-infinite-scroller)に書いてあります。
loadMore
loadMoreについては、ユーザーがスクロールしてアイテムを要求した時のコールバックが指定されます。loadMoreに指定したコールバックの引数にはpage番号が指定され、呼ばれるたびに1から増えていきます。
上記のコードではページ番号をもとにクエリを投げ、返ってきたTweetをStateに順次保存しています。
hasMore
ロードするアイテムがあるか判断します。falseになったらスクロールを感知するリスナーは削除されます。上記コードではloadMoreコールバックにて、lighthouseで用意されたpaginatorInfoの情報からhasMorePagesフィールドの値をstateに保存して、InfiniteScrollのpropsに設定しています。
loader
ロードしている最中に表示できるコンポーネントを指定することができます。
useWindow
falseを指定することでoverflow:autoで正常に動くようになりました。
※trueだと中途半端なタイミングでずっとloadingとなってしまう。
実行結果
スクロールのたびに3件づつデータを取得することができています!
では!
Discussion