13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React】React QueryのuseInfiniteQueryで無限スクロールを実装

Posted at

#はじめに
React QueryのuseInfiniteQuery()で無限スクロールを実装したので記事にまとめました。

「React Queryって何?」という方は、よろしければ前回の記事もご覧ください。

#useInfiniteQueryとは
useInfiniteQuery()はデータの一部で返される次のクエリを追跡します。
useQuery()とは返すdataの中身が異なり、pagespageParamsの2つのプロパティを含んだオブジェクトとなります。
pagesはクエリの結果を配列で返し、pageParamsは実行されたクエリのキーを配列で返します。

上がpages、下がpageParamsの結果の例となります。
スクリーンショット 2021-12-04 11.56.58.png

また、useInfiniteQuery()の記述例は以下のようになります。

  const {
    data,
    fetchNextPage,
    hasNextPage,
    isLoading,
    isFetching,
    isError,
    error,
  } = useInfiniteQuery(
    'sw-people',
    ({ pageParam = initialUrl }) => fetchUrl(pageParam),
    {
      getNextPageParam: (lastPage) => lastPage.next || undefined,
    }
  );

pageParamには初期値としてdefaultUrlが設定されていますが、optionであるgetNextPageParamによって更新されます。
以上の例では、最新ページのデータlastPageから次のpageParamlastPage.next || undefinedとして設定していますが、allPagesというパラメータも利用することができます。
このように、pageParamの現在値はReact Queryによって管理されます。

また、useInfiniteQuery()が返すオブジェクトのプロパティには、useQuery()にはなかった以下のようなものが存在します。

  • fetchNextPage: 次ページのデータのフェッチを許可する関数
  • hasNextPage: getNextPageParamによってpageParamが更新されたらtrueを返す(undefinedのときfalse)
  • isFetchingNextPage: fetchNextPageで次ページのデータをフェッチしている間trueを返す(loadingのフラグに使用)

これまでに登場したワードを実際のデータ取得フローあてはめると以下のようになります。

  1. コンポーネントがマウントされて最初のページをフェッチする
  2. getNextPageParampageParamを更新する
  3. hasNextPagetrueであれば、イベント(スクロールやボタンクリック)によってfetchNextPageを実行する
  4. hasNextPageundefinedになるまで2→3を繰り返す

#実装例
useInfiniteQuery()とReact Infinite Scrollerを使って、無限スクロールを実装します。

InfinitePeople.jsx
import InfiniteScroll from 'react-infinite-scroller';
import { useInfiniteQuery } from 'react-query';
import { Person } from './Person';

const initialUrl = 'https://swapi.dev/api/people/';
const fetchUrl = async (url) => {
  const response = await fetch(url);
  return response.json();
};

export function InfinitePeople() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isLoading,
    isFetching,
    isError,
    error,
  } = useInfiniteQuery(
    'sw-people',
    ({ pageParam = initialUrl }) => fetchUrl(pageParam),
    {
      getNextPageParam: (lastPage) => lastPage.next || undefined,
    }
  );

  if (isLoading) return <div className="loading">Loading...</div>;
  if (isError) return <div>Error! {error.toString()}</div>;

  return (
    <>
      {isFetching && <div className="loading">Loading...</div>}
      <InfiniteScroll loadMore={fetchNextPage} hasMore={hasNextPage}>
        {data.pages.map((pageData) => {
          return pageData.results.map((person) => {
            return (
              <Person
                key={person.name}
                name={person.name}
                hairColor={person.hair_color}
                eyeColor={person.eye_color}
              />
            );
          });
        })}
      </InfiniteScroll>
    </>
  );
}

react-infinite-scrollからInfiniteScrollをインポートして、Personコンポーネントをラップします。
loadMoreプロパティにfetchNextPageを、hasMoreプロパティにhasNextPageを設定することで次ページのデータのフェッチを制御することができるようになります。

#参考資料

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?