본문 바로가기

리액트

포켓몬 API를 사용하여 포켓몬 도감 만들기

포켓몬 API를 활용하여 도감 만들기

API 요청

  • 포켓몬 API는 내부에 데이터가 복잡한 것 같다.
  • axsios.all을 사용하여 가져온 150개에 대에터에 병렬요청을 하였다.
  • 이 복잡한 데이터를 내가 원하는 것만 가져오기 위해서 map(), find()로 원하는 데이터만 가져왔다.

연결

  • 데이터를 무한 스크롤을 사용하여 연결을 해주었다.

useInfiniteQuery

  • 쿼리를 사용하여 무한 스크롤을 쉽게 구현할 수 있다.
  • data에는 모든 불러온 데이터를 담은 객체를
  • fetchNextPage()는 다음 페이지 데이터를 불러오는 함수이다.
  • hasNextPage는 다음 페이지가 있다면 boolean 값으로 리턴 한다. 있다면 true를 반환
  • isFetching 현재 데이터를 가져오고 있는 중인가? boolean
  • isFetchingNextPage 다음 페이지 데이터를 가죠오는 중인지 여부 boolean
  • isLoading 초기 데이터 로딩 중 여부 boolean
  • isError API 요청 실패 여부 boolean
  • error 오류 발생 시 오류 객체 boolean
      const { data, fetchNextPage, hasNextPage, isLoading, isError } =
    useInfiniteQuery({
      queryKey: ['pokemon-species'],
      queryFn: ({ pageParam = 0 }) => getPokemon(pageParam),
      initialPageParam: 0,
      getNextPageParam: (lastPage) => {
        return lastPage?.nextPage ?? undefined;
      },
    });

IntersectionObserver

  • 사용자가 스크롤을 내릴 떄 자동으로 fetchNextPage()는 실행한다.
  • 특정 요소가 뷰포트(화면)에 나타나는지 감지하는 API이다.
  • entries[0].isIntersecting === true 일 떄, 요소가 화면에 나타내는지를 의미하고 이를 활용하여 스크롤이 끝에 도달할 떄 자동으로 다음 데이터를 로드 한다.
  • observer.observe(element)를 호출하면 엘리먼트의 가시성을 감시, observerRef.curren 무한 스크롤을 감지할 대상 요소를 선택한다. ref로
  • 컴포넌트가 언마운트되거나 useEffect가 재실행될 떄 기존 observer를 제거하여 메뮈 누수를 방지 한다.
  • unobserve()를 호출하면 해당 요소의 감시가 중단
  • { threshold: 1.0 } 요소가 화면에 어느 정도 보여야 실행 되는가?
      useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && hasNextPage) {
          fetchNextPage();
        }
      },
      { threshold: 0.5 },
    );

    if (observerRef.current) {
      observer.observe(observerRef.current);
    }

    return () => {
      if (observerRef.current) {
        observer.unobserve(observerRef.current);
      }
    };
  }, [fetchNextPage, hasNextPage]);

🛠 React Query 인피니트 스크롤에서 무한 로딩 발생

  • React Query의 useInfiniteQuery를 활용하여 무한 스크롤을 구현했다.
  • 그런데 화면에서 계속 스피너(로딩 화면)만 보이고, 데이터가 나오지 않는 문제가 발생했다.

🔍 원인 분석

  • isLoadinguseInfiniteQuery에서 제공하는 것이 아니라 내가 기존에 만들었던 state를 사용하고 있었다.
  • isLoading을 따로 관리하는 useState를 만들어서 데이터 로드 완료 후에도 true 상태로 남아있었다.

🚀 해결 방법

  • 기존 useState를 삭제하고, React Query의 isLoading을 직접 사용했다.
  • 코드 변경 전:
        const [loading, setLoading] = useState(true);
    if (loading) return <Loading loading={loading} />;
    

🎯 배운 점

  • React Query는 자체적으로 로딩 상태(isLoading)를 관리하므로, 별도의 state를 만들 필요가 없다.
  • 잘못된 state 관리는 무한 로딩 같은 예기치 않은 버그를 발생시킬 수 있다.
  • useState로 상태를 추가하기 전에 React Query가 제공하는 상태값을 먼저 확인하자!

지금까지 만든 화면