✨refactor: useInfiniteQuery 적용시키기

Jieunmoon·2023년 10월 14일
post-thumbnail

📌 useInfiniteQuery란?

무한 스크롤을 간편하게 구현해주는React Query 라이브러리로 useInfiniteQuery를 사용하면 데이터 로딩과 관리를 간단하게 처리, 복잡한 데이터 요구 사항을 간단한 코드로 다루기 위해 사용하였다.

useInfiniteQuery적용 전에 사용한것

🐞
1. useState로 page를 관리해주려 했으나 싱크가 맞지않는 문제 발생

  • AllProductList나 CategoryList컴포넌트 둘다 state로 관리하면 비동기때문에 싱크가 안맞는 현상 발생
  1. useRef사용으로 싱크해결
    다만 AllProductList(메인페이지)에서 보이지 않는것은 CategoryList(필터상품페이지)처럼 필터 부분이 없어서 필터를 누르면 페이지 넘버를 초기화해주고 1페이지부터 데이터를 받아오는 것이 없고 무한으로 그냥 다음페이지만 계속해서 받아오기때문에 안보이는것이였고 싱크를 맞추기 위해 직접 DOM에 접근하고 조작할 수 있는 useRef사용
  • prouducts에 데이터를 보관
  const [products, setProducts] = useState<Product[]>([]);
  const [ref, inView] = useInView();
  const pageRef = useRef(1);

  const productFetch = async () => {
    try {
      let url = `https://서버링크/api/product/category/${category}?pageNumber=${pageRef.current}`;
      if (age !== null && age !== undefined) {
        url += `&ageCategory=${age}`;
      }
      if (gender !== null && gender !== undefined) {
        url += `&genderCategory=${gender}`;
      }
      const response = await axios.get(url);
      setProducts((prevProducts) => [
        ...(pageRef.current === 1 ? [] : prevProducts),
        ...response.data,
      ]);
      pageRef.current = pageRef.current + 1;
    } catch (error) {
      console.error(error);
    }
  };

  useEffect(() => {
    if (age === '나이' && gender === '성별') return;
    pageRef.current = 1;
    productFetch();
  }, [age, gender]);

  useEffect(() => {
    if (inView) {
      console.log(inView, '무한 스크롤 요청', pageRef);
      productFetch();
    }
  }, [inView]);

useInfiniteQuery적용 및 api로직 분리

  • 기존데이터를 유지시키면서 받아온 데이터를 따로 추가해줄 필요 X (React Query 라이브러리를 사용할 때 자동으로 생성되는 속성 pages가 페이지별 데이터를 배열로 관리하기 때문)
  • 페이지를 state로 관리해주지 않음
  • 리액트 쿼리 useInfiniteQuery에서 제공해주는 함수isFetching 을 이용해 로딩처리 가능
  • status를 이용한 error 처리 가능
  const [ref, inView] = useInView();
  const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage, status } =
    useInfiniteQuery('products', async ({ pageParam = 1 }) => fetchProducts(pageParam), {
      getNextPageParam: (lastPage, pages) => {
        if (lastPage.length === 0) {
          return undefined;
        }
        return pages.length + 1;
      },
    });

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

💡 데이터를 받아올 때 로딩과 에러처리 부분

  • 이 부분에 UI를 추가하여 데이터를 받아오는 중 일때 Loading UI를 보여줄 수 있고, error일때 에러처리를 상태에 따라 간편하게 해줄 수 있다.
      {isFetching ? (
        <p>🔎Loading...</p>
      ) : status === 'error' ? (
        <p>😥데이터를 불러오는데 실패했습니다</p>
      ) : null}

💻 결과물

📝 프로젝트에 적용한 useInfiniteQuery 속성정리

  • data : 서버로부터 받아온 현재 페이지의 데이터를 포함하는 배열 또는 객체
  • fetchNextPage : 다음 페이지의 데이터를 가져오도록 요청하는 함수 (호출 시 React Query가 다음 페이지의 데이터를 가져와서 data에 추가함)
  • hasNextPage : 다음 페이지가 존재하는지 여부를 나타내는 불리언 값
  • isFetching : 현재 데이터를 가져오는 요청이 진행중인지 나타내는 불리언 값
  • isFetchingNextPage : 다음 페이지의 데이터를 가져오는 요청이 진행중인지를 나타내는 불리언 값
  • status : 현재 쿼리 상태를 나타내는 문자열. 일반적으로 "idle" (대기 중), "loading" (불러오는 중), "error" (에러), "success" (성공) 중 하나가 됩니다. 현재 쿼리의 상태를 확인하여 UI를 업데이트하는 데 사용
  • pageParam : 기본값은 1로 설정되어 있으며, 이는 처음에는 1페이지부터 시작한다는 의미로 페이지 번호는 1부터 시작하며, 페이지마다 1씩 증가

0개의 댓글