본문 바로가기
FE/react

[React-query] useInfiniteQuery의 select로 반환값 변환하기

by s0ojin 2023. 3. 31.

 

 

임의로 qeury의 반환값을 useState로 수정하고 사용하여 생긴 문제


 useInfiniteQuery로 받아온 데이터들만 화면에 바로 렌더링되지않고, 꼭 refetch가 일어나야만 그림이 그려지는 문제가 생겼다.

처음엔 useInfiniteQuery 훅의 문제인가했는데 react-query devtool을 확인해보면 분명 정상적으로 캐싱이되고 있었다.

 

생각해보니 useInfiniteQuery의 data구조가 조금 복잡해서 postList라는 state를 만들어서 fetch성공시 데이터를 평탄화시키도록 해놨는데, 그 부분이 문제였다.

  const [postList, setPostList] = useState<IArticleData[]>([]);
  const { isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery(
    ['articles'],
    ({ pageParam = 1 }) => getArticles({ pageParam }),
    {
      onSuccess: (data) => {
        setPostList(() => data?.pages.flatMap((page) => page.data));
      },
      getNextPageParam: (lastPage, allPages) => {
        const nextPage = allPages.length + 1;
        return lastPage.data.length === 0 ? undefined : nextPage;
      },
    },
  );

 

사실 react-query에는 반환하는 data값을 가공하고 정제할 수 있는 select 옵션이있다. 위처럼 써도 문제가 없을거라 생각해서 썼는데 역시나 어김없이 문제가 발생한다...^^ 역시 라이브러리는 정해진 루트대로 쓰는게 베스트인 것 같다.

 

 

select


  • This option can be used to transform or select a part of the data returned by the query function. It affects the returned data value, but does not affect what gets stored in the query cache.
  • select는 반환하는 데이터 값을 수정할 수 있다. 다만 반환값을 변환할 뿐 저장되는 캐시 데이터에는 영향을 미치지 않는다.
❗️Note: When using options like initialData or select in your query, make sure that when you restructure your data that it still includes data.pages and data.pageParams properties, otherwise your changes will be overwritten by the query in its return!

useInfiniteQuery에서 select를 사용할 땐 pages와 pageParams를 반드시 같이 리턴해주어야한다. 그렇지 않으면 쿼리를 변화할 때 데이터를 덮어씌우는 오류가 발생할 수 있다고한다. 

 

 

공식사이트에 나와있는  select의 사용법은 다음과 같다.

// useQuery select 사용예시
function User() {
  const { data } = useQuery(['user'], fetchUser, {
    select: user => user.username,
  })
  return <div>Username: {data}</div>
}

// useInfiniteQuery select 사용예시
useInfiniteQuery({
  queryKey: ['projects'],
  queryFn: fetchProjects,
  select: (data) => ({
    pages: [...data.pages].reverse(),
    pageParams: [...data.pageParams].reverse(),
  }),
})

 

코드 수정


  const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery<
    AxiosResponse,
    AxiosError,
    IArticleData
  >(['articles'], ({ pageParam = 1 }) => getArticles({ pageParam }), {
    getNextPageParam: (lastPage, allPages) => {
      const nextPage = allPages.length + 1;
      return lastPage.data.length === 0 ? undefined : nextPage;
    },
    select: (data) => ({
      pages: data.pages.flatMap((page) => page.data),
      pageParams: data.pageParams,
    }),
  });

 

 

 

댓글