pagination을 구현하며 공부하게된 React Query 사용법을 공유하고자 합니다.
이번에 React Query를 이용하며 cache와 pagination을 구현하며 사용한 기능은 useQuery입니다. github api를 이용하여 검색어를 받아 레포지토리를 검색하고 결과 데이터를 caching하기 위해 사용했습니다.
// const { data, isFetching } = useQuery(queryKey, queryFn, { options })
const { data, isFetching } = useQuery<RepoResult>(
["repos", { name: query.repo as string, page: page }],
() => fetchReposWithQuery<RepoResult>(query.repo as string, page),
{ keepPreviousData: true, refetchOnWindowFocus: true, staleTime: 60000, enabled: !!query.repo }
);
useQuery는 파라미터로 queryKey, queryFn, options를 가집니다.
queryKey는 배열 또는 string을 받을 수 있습니다. queryKey가 변경됐을 때 useQuery에서 data를 업데이트합니다.
queryKey로 데이터를 구분하여 다른 컴포넌트에서 useQuery로 동일한 키를 입력하면 데이터를 api 요청없이 사용할 수 있습니다.
queryKey를 배열로 할 때 순서를 주의해야합니다
- [key, name, page] !== [key, page, name]
순서가 바뀌면 key가 다르다고 인식되어 새로 api를 호출합니다.
이럴 때 객체를 이용하면 좋습니다.- [key, {name: name, page: page}] === [key, {page: page, name: name}]
객체 안에서 순서를 다르게 입력해도 같은 key로 인식합니다.
queryFn은 데이터를 호출하는 함수를 받습니다.
fetchReposWithQuery 함수는 인자로 레포지토리 이름, 페이지를 받아 github api 검색 데이터를 받아오는 함수입니다.
const fetchReposWithQuery = async <T>(repo: string, page: number): Promise<T> => {
const info = await axios.get(
`https://api.github.com/search/repositories?q=${repo}+in:name&page=${page}&per_page=10`,
{
headers: headers,
}
);
return info.data;
};
저는 keepPreviousData, refetchOnWindowFocus, staleTime, enabled option을 사용했습니다.
keepPreviousData: 데이터 refetch될 때 이전 데이터를 유지하는 지를 정하는 옵션입니다. false로 하면 page가 바뀔 때 data가 비워진 후 새로운 data를 받아옵니다. true이면 새로운 data를 다 받아온 후 data를 교체합니다.
- keepPreviousData가 true일 때 isSuccess, isLoading 값이 처음 데이터를 불러오기 시작할 때, 불러온 후 바뀌고 그 후로는 바뀌지 않습니다.
- keepPreviousData가 false일 때 isSuccess, isLoading 값이 queryKey가 바뀔 때마다 변합니다.
pagination을 구현할 때는 true로 하는게 좋습니다.
true일 때 window에 focus되었을 때 데이터를 refetch합니다.
cache 데이터의 유효기간을 ms단위로 설정합니다. cache 데이터를 refetch할 때 staleTime이 지났다면 queryFn를 호출하여 데이터를 불러온 후 cache를 교체합니다.
enabled가 false라면 데이터를 불러오지 않습니다. useQuery가 return하는 refetch 메소드 등을 이용하여 수동으로 refetch를 해야합니다.
- 이 옵션을 설정하지 않았을 때 query.repo가 없다면 undefined를 검색어로 api를 호출한 검색결과가 fetch되는 문제가 있었습니다.
enabled: !!query.repo를 통해 query.repo가 undefined일 때 data를 반환하지 않게 하였습니다.
useQuery의 return 값 중에 저는 data, isSuccess, isLoading, isFetching을 사용했습니다.
queryFn을 호출하여 얻은 결과 또는 queryKey에 따른 cache data를 반환합니다.
queryFn이 호출되었을 때 false를 반환합니다. queryFn가 정상적으로 완료되었을 때 true를 반환합니다.
cache data가 없고 queryFn을 통한 fetch가 진행 중일 때 true를 반환합니다. fetch가 끝나면 false를 반환합니다.
cache data를 불러올 때, queryFn을 호출할 때 항상 true를 반환합니다.
loading상태를 나타내고 싶을 때 주로 사용합니다.
pagination을 구현할 때 keepPreviousData가 false라면 page가 바뀔 때마다 useQuery는 새로운 query라고 생각하여 isSuccess와 isLoading 값이 변하게 됩니다. keepPreviousDatat를 true로 하면 첫 페이지에서만 isSuccess와 isLoading 값이 변하고 페이지 이동할 때 더이상 isSuccess와 isLoading은 변하지 않게 됩니다.
react-query의 useQuery를 사용하면 쉽게 cache를 구현할 수 있어서 편리합니다.