infinity scroll 구현하기(useInfiniteQuery, useInView)

조승윤·2022년 9월 27일

이전 글에서 react-query에 대해 장점을 설명 할 때 useInfiniteQuery에 대해 언급하였고 간단하게 채팅을 만들때도 사용했다. useInfiniteQuery와 intersection-observer의 useInView를 사용해 간단하게 infinity scroll을 구현하는 글을 기록하기로 했다.

기존에 infinity scroll을 구현하기위해 scroll 이벤트감지, redux-saga, infinity scroll라이브러리, hook만들어서 사용하기 등 구현 할 수있는 방법은 거의 다 해보았다. 그 결과 intersection-observer의 useInView와 react-query의 useInfiniteQuery를 사용 했을때 가장 깔끔하고 좋았다.

구현영상

글 목록에서 세부내용으로 화면이 바뀐후 돌아왔을때 스크롤 위치가 초기화 되지 않는다

소스코드

import React, { useEffect } from "react";
import { useInfiniteQuery } from "react-query";
import { useInView } from "react-intersection-observer";
import { Link } from "react-router-dom";
import axios from "axios";

const ScrollTest = () => {
  const { ref, inView } = useInView(); // ref가 화면에 나타나면 true 또는 false를 반환한다.

  const { isLoading, isError, error, data, fetchNextPage, isFetching, isFetchingNextPage, refetch, hasNextPage } = useInfiniteQuery(
    "chat_list",
    async ({ pageParam = 1 }) => {
      const { data } = await axios.get(`api&page=${pageParam}`);
      return data;
    },
    {
      onSuccess: (data) => {// 성공시 호출},
      refetchOnWindowFocus: false,
      staleTime: Infinity,
      cacheTime: Infinity,
      getNextPageParam: (lastPage) => {
        return lastPage.page === 3 ? false : lastPage.page + 1; //테스트용으로 3페이지로 페이지 제한 실제로 사용할때는 api에서 내려오는 값을 이용해야함
      },
    }
  );

  useEffect(() => {
    if (inView) {
      fetchNextPage();
    }
  }, [inView]);

  //viewport에 Load More 버튼이 보여지게 되면 true를 반환하고 useEffect에서 fetchNextPage();를 실행해 다음페이지를 불러오게 된다.
  
  return (
    <>
      {data?.pages.map((page) =>
        page.result.map((item) => (
          <div className="div_box" key={item.id}>
            <Link to={`/test/detail/${item.id}`}>{item.id}</Link>
          </div>
        ))
      )}
      <div>
        {!hasNextPage || isFetchingNextPage ? (
          <div>더 이상 표시할 데이터 없음</div>
        ) : (
          <button onClick={fetchNextPage} disabled={!hasNextPage || isFetchingNextPage} ref={ref}>
            Load More
          </button>
        )}
      </div>
    </>
  );
};

export default ScrollTest;

useInfiniteQuery docs
react-intersection-observer npm

0개의 댓글