리액트 쿼리로 무한스크롤 구현하기

수딩·2022년 10월 7일
0

동적 데이터 로드를 위한 무한 쿼리

  1. 설치 !
npm install --legacy-peer-deps

앞으로 사용할 react infinite scoller의 의존성을 설정한 방식 때문에
--legacy-peer-deps 플래그를 사용하지 않으면 오류가 난다.

useInfiniteQuery 입문

useQuery 와 useInfiniteQuery의 차이점

  • useQuery에서 데이터는 단순히 쿼리 함수에서 반환되는 데이터인 반면,
    useInfiniteQuery에서 객체는 두개의 프로퍼티를 가지고 있다.
  • 하나는 데이터 페이지 객체의 배열인 페이지고 페이지에 있는 각 요소가
    하나의 useQuery에서 받는 데이터에 해당한다.
    다른 하나는 pageParams이다. 각 페이지의 매개변수가 기록되어 있다.
  • 모든 쿼리는 페이지 배열에 고유한 요소를 가지고 있고 그 요소는 해당쿼리데 대한 데이터에 해당된다.
    페이지가 진행되면서 쿼리도 바뀐다.
  • pageParams는 검색된 쿼리의 키를 추적한다. 흔하게 사용되지는 않음
  • 구문에서도 차이가 있다.
useInfiniteQuery('sw-people',({ pageParam = defaultUrl }) => fetchUrl(pageParam)

InfiniteQuery에는
getNextPageParam: (lastPage, allPages) 옵션이 있다.
다음 페이지 혹은 모든 페이지에 대한 데이터를 가져오고, pageParam을 업데이트 해준다

프로퍼티

  • fetchNextPage
    사용자가 더 많은 데이터를 요청할 때 호출하는 함수
  • hasNextPage
    getNextPageParam 함수의 반환값을 기반으로 한다.
    이 프로퍼티를 useInfiniteQuery에 전달해서 마지막 쿼리의 데이터를 어떻게 사용할지 지시. undefined인 경우 더이상 데이터가 없다는 거고 useInfiniteQuery에서 반환 객체와 함께 반환된 경우에는 hasNextPage는 거짓이 된다.
  • isFetchingNextPage
    useInfiniteQuery는 다음페이지를 가져오는지 아니면 일반적인 fetching인지 구별이 가능하다!

useInfiniteQuery 호출

사용해줄 페이지에 useInfiniteQuery를 임포트해주자

import { useInfiniteQuery } from 'react-query';

그런다음 함수형 컴포넌트에서 사용

export function InfinitePeople() {
  const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(
    'sw-people',

반환해줄 객체는 data 이다.
페이지를 계속 로드할 때 여기에 데이터의 페이지가 포함될것

fetchNextPage는 더 많은 데이터가 필요할 때 어느 함수를 실행할지를
infiniteScroll에 지시하는 역할을 한다.

hasNextPage는 수집할 데이터가 더 있는지를 결정하는 boolean 이다.

export function InfinitePeople() {
  const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(
    'sw-people',
   ({ pageParam = initialUrl }) => fetchUrl(pageParam),

useInfiniteQuery는 몇가지 인수를 사용하는데 쿼리키, 쿼리 함수를 입력해줬다.
이 쿼리 함수는 객체 매개변수를 받고 프로퍼티 중 하나로 pageParam을 가지고 있다.
useInfiniteQuery의 모든것이 pageParam 에 달려있다.
왜냐면
pageParam은 fetchNextPage가 어떻게 보일지 결정하고 다음 페이지가 있는지 결정하기 때문이다.
fetchUrl이 하는 일은 Url인 pageParam을 가져와서 json을 반환해 준다.
pageParam은 기본값을 줘야한다. useInfiniteQuery를 처음 실행할 땐 pageParam이 설정돼있지 않기 때문이다.

이제 getNextPageParam에 옵션을 줘보자!

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

이 옵션은 lastPage 를 가진 함수이다.
필요하면 allPage를 두번째 인자로 넣을 수 있지만 지금은 필요가 없기 때문에 lastPage만 넣어줬다.
lastPage를 가져와서 pageParam을 lastPage.next로 작성해주었다.
fetchNextPage를 실행하면 next 프로퍼티가 무엇인지에 따라 마지막 페이지에 도착한 다음 pageParam을 사용하게 되는 형식이다.

hasNextPage는 undefined를 반환하는지, 아닌지에 따라 결정이 된다.
그래서 lastPage.next가 거짓이면 undefined를 반환하도록 만들어주었다.

React Infinite Scroller

나는infinite scroller을 사용하여 무한스크롤을 구현할 것이다

 npm i react-infinite-scroller

시작하기 전에 flow를 보면
infiniteScroller은 두개의 프로퍼티가 있다.

  • loadMore = {fetchNextPage}
    데이터가 더 필요할 떄 불러와 useInfiniteQuery에서 나온 fetchNextPage 함숫값을 이용한다.
  • hasMore = {hasNextPage}
    useInfiniteQuery에서 나온 객체를 해제한 값을 이용한다.

무한스크롤 컴포넌트는 스스로 페이지의 끝에 도달함을 인식하고 fetchNextPage를 불러온다.
그러면 데이터 프로퍼티에서 데이터에 접근할 수 있는데
useInfiniteQuery 컴포넌트에서 나온 객체를 이용한다
배열인 페이지 프로퍼티를 이용해서 그 페이지 배열의 맵을 만들어 데이터를 표시할 수 있게
해주는 역할을 한다.

코드를 작성해보쟈

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

useInfiniteQuery 를 실행해 반환된 객체에서 나온 프로퍼티들을 나열, 쿼리키 설정, 쿼리함수를 작성해주었다.
이 쿼리 함수는 useInfiniteQuery의 pageParams를 쓰는데
initialUel 에서 시작해 pageParam 값으로 fetchUrl을 실행한다.
그 다음 getNextPageParam은 이전페이지(lastPage)의 다음 프로퍼티를 불러와
새 페이지 데이터가 있을 때마다 pageParam에 지정해준다 .
API에서 지정해준대로 이 함수의 값이 null 인 경우에는 undefined 값을 낸다.

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

  return (
    <InfiniteScroll loadMore={fetchNextPage} hasMore={hasNextPage}>
      {data.pages.map((pageData) => {
        return pageData.results.map((person) => {
          console.log(person);
          return (
            <Species
              key={person.name}
              name={person.name}
              language={person.language}
              averageLifespan={person.average_lifespan}
            />
          );
        });
      })}
    </InfiniteScroll>
  );

InfiniteScroll 컴포넌트에서

  • loadMore함수는 fetchNextPage가 되고
    fetchNextPage는 useInfiniteQuery의 영향을 받아 어떤 쿼리 함수든
    pageParam 값을 쓰게 되고 pageParam값은 데이터가 추가되면 갱신된다.

  • hasMore함수는 infiniteScroll 컴포넌트가 계속 데이터를 불러올지를 결정하는 역할을 한다. 이 함수는 hasNextPage 프로퍼티의 영향을 받고 pageParam이 정의되지 않아 거짓이 되는 경우도 lastPage.next를 통해 다음 프로퍼티가 없거나 프로퍼티가 거짓인 경우도 정의했다!

이렇게 다 설정해준 뒤 데이터를 매핑해주면 끝!

profile
Front-End Developer ✨

0개의 댓글

관련 채용 정보