https://www.udemy.com/course/react-query-react/
udemy의 'React Query / TanStack Query : React로 서버 상태 관리하기' 강의를 보고 정리했습니다.
리액트 쿼리란?
TanStack Query는 리액트 앱의 서버 상태를 관리하는 라이브러리이다.
클라이언트 상태란 웹 브라우저 세션과 관련된 모든 정보를 의미한다. 이는 서버와 관련이 없다. 서버 상태는 클라이언트에 표시하는데 필요한 데이터를 말하며, db에 저장되는 블로그 게시물 데이터 등이 이에 해당한다. 게시물을 표시하기 위해 클라이언트에 데이터가 있어야 하지만, 데이터는 여러 클라이언트에 표시될 수 있도록 서버에 저장된다.
리액트 쿼리는 클라이언트에서 서버 데이터 캐시를 관리한다. 리액트 코드에 서버 데이터가 필요할 때, fetch나 axios를 사용해 서버로 바로 이동하지 않고, React Query 캐시를 요청한다.
리액트 쿼리의 역할은 리액트 쿼리 클라이언트를 어떻게 구성했느냐에 따라, 해당 캐시의 데이터를 유지/관리하는 것이다. 데이터를 관리하는 것은 리액트 쿼리이지만, 서버의 새 데이터로 캐시를 업데이트하는 시기를 설정하는 것은 사용자의 몫이다.
리액트 쿼리 사용법
1. npm install @tanstack/react-query
명령어를 통해 라이브러리를 설치한다.
2. query Client를 생성한다.
- 쿼리를 관리하고, 서버 데이터도 저장하는 클라이언트이다.
3. 자식 컴포넌트에 캐시 및 클라이언트 구성을 제공할 queryProvider를 적용한다
- 이 Provider는 queryClient를 값으로 사용한다.
4. 서버에서 데이터를 받기 위해 useQuery 훅을 사용한다.
우선 Query Client 생성하는데, 여기에는 쿼리, 캐시, 쿼리 캐시를 조작하는 도구가 속한다. 하지만 대개 이 도구들을 직접 사용하지는 않는다. 대신 쿼리 클라이언트를 속성으로 쓰는 QueryClientProvider를 추가한다. 그러면 Provider 자식 컴포넌트가 리액트쿼리 훅을 사용한다.
QueryClicent와 QueryClientProvider를 react query로부터 불러온다.
queryClient를 생성하고, queryClientProvider의 속성으로 넣어준다. 이제 Provider의 자식들은 리액트 쿼리의 다른 도구들도 사용가능하며, 캐시를 포함한 query Client에 접근 가능하게 된다. 이제 데이터를 불러와볼 것이다.
Posts 컴포넌트(리액트 쿼리를 사용할 컴포넌트)로 이동 후 tanstack query로부터 useQuery를 불러온다.
useQuery는 많은 속성을 가진 객체를 반환하는데, 이를 구조 분해 할당한다.
useQuery는 인자로 옵션 객체를 받는다. 첫 번째는 queryKey이다. 객체이므로 순서는 상관없다. queryKey는 항상 배열이며, 쿼리 캐시 내의 데이터를 정의한다. 다음으로는 queryFn를 추가해야 한다. 데이터를 가져오기 위해 실행할 함수이다.
이제 data가 정의되었고, 포스트를 가져오기 위해 필요한 옵션을 useQuery에 제공했다.
하지만 받아온 데이터를 map 함수로 출력하려고 하면 undefined에 map을 사용하고 있다는 에러가 나온다. 이는 data가 정의되지 않았다는 뜻과 같다.
fetchPosts는 비동기 함수로, 결과반환에 시간이 좀 걸리며, 바로 data가 정의되지 않는다. 즉 fetchPosts가 결과를 반환한 후에야 data가 정의되기에 에러가 나오는 것은 당연하다.
임시방편으로 데이터가 정의되지 않았을 때 빈 <div> 태그를 반환하게 하면, 비동기 처리가 진행되는 동안 빈태그가 출력되고, 데이터를 가져왔을 때 해당 데이터가 잘 받아와 지는 것을 확인할 수 있다. 리액트 쿼리에는 이런 상황을 해결할 수 있는 도구들이 존재한다.
useQuery에서 반환되는 객체의 다른 속성들이 많은데, 위의 상황을 해결하기 위해 isLoading과 isError를 살펴볼 것이다.
데이터 로딩 중이나, 에러 발생 여부를 알려주는 bool값이다.
isLoading과 isError
우선 isLoading을 활용해서, 만약 로딩 중일 때 <h3>를 반환하게 한다.
로딩되는 동안 isLoading의 값은 true가 되고, 따라서 'Loading…' 출력되는 것을 확인할 수 있다.. 그리고 로딩이 끝나면 isLoading은 false가 되며 받아온 데이터가 출력된다. data가 비동기 처리로 인해 undefine를 반환하는 상황에서도 오류가 없어지는 것!
isError를 통해 에러도 제어할 수 있다. 기본적으로 리액트 쿼리는 세 번 시도 후 데이터를 가져올 수 없다고 판단한다. 그래서 시도하는 동안은 isLoading이 true을 반환한다. 그리고 최종적으로 데이터를 받아오는 데 실패하며 isError가 true로 변경되며 반환하는 값이 출력되는 것을 확인할 수 있다.
useQuery가 반환하는 error 속성을 사용할 수도 있다. error 속성은 에러가 있다고 판단되면 발생한 에러 객체를 보내준다. 그래서 실제 에러 내용을 알 수 있다. 사용자에게 알리거나 로그로 보낼 수 있다.
isLoading vs isFetching
isLoading 이외에도 isFetching이 있다.
isFetching는 비동기 queryFn이 아직 해결되지 않았다는 것을 뜻한다. fetch가 완료되지 않았지만 axios 호출 같은 다른 종류의 데이터를 가져오는 작업 중일 수도 있다. isLoading은 그 하위 집합으로, 로딩 중이라는 것을 말한다. queryFn이 미해결이지만, 캐시 된 데이터도 없다. 쿼리를 전에 실행한 적이 없어서 데이터를 가져오는 중이고, 캐시 된 데이터도 없어서 보여줄 수 없다.
별 차이 없어 보여도 페이지네이션을 볼 때 캐시 된 데이터가 있는지 없는지 구분하는 것이 중요하다.
Stale Data
데이터가 오래됐다는 건 유효기간이 만료됐다는 뜻이다. 사용기간이 지났다는 것이며 다시 가져올 준비가 된 것이다. 하지만 데이터는 여전히 캐시에 남아있다. 즉 데이터가 stale로 표시돼도 캐시에서 삭제된 건 아니다. 그저 데이터를 다시 검증해야 한다는 뜻이다.
데이터 refetch는 오직 데이터가 stale일 때만 트리거 된다. 예를 들면 컴포넌트가 다시 마운트 되거나, 브라우저 창이 리포커싱 할 때이다.
staleTime은 데이터의 최대 수명으로 생각할 수 있다. 서버로부터 가장 신선한 데이터 버전을 가져오기 전에, 데이터를 얼마나 살려둘 것인지 우리가 데이터가 오래됐을 가능성을 얼마나 용인할 것인지를 나타내는 것
staleTime을 2초로 설정했다. 데이터는 2초 동안 fresh 상태를 유지할 것이고, 만약 그동안 refetch 트리거가 발생했다면 데이터를 다시 가져오지 않았을 것이다. 데이터가 stale이어야 refetch 트리거가 서버에서 데이터를 다시 가져오기 때문이다.
react-query의 staleTime은 기본적으로 0초이다. 즉 항상 stale 상태를 유지하며, 서버에서 다시 데이터를 가져와야 하는 상태인 것이다. 그러면 클라이언트에 stale 데이터가 있을 가능성이 크게 줄어든다.
gcTime라는 속성도 있다. staleTime과 gcTime을 혼동하기 쉽다. staleTime은 데이터를 다시 가져와야 할 때를 알려주고, gcTime은 데이터를 캐시에 유지할 시간을 결정한다.
쿼리가 캐시에 있으나 사용되지 않을 때, 이에 대한 유효기간이 정해져 있는 데, 그 유효기간이 gcTime이다.
gcTime이 지나면 데이터는 캐시에서 사라진다. gcTime의 기본 시간은 5분이며 데이터가 페이지에 표시된 후부터 시간이 측정된다. 따라서 gcTime은 데이터가 페이지에 표시될 때는 진행되지 않는다. 데이터가 react앱에서 더 이상 사용되지 않으면 진행된다.
캐시는 백업 데이터이다. 서버에서 refresh 데이터를 가져오는 동안 캐시를 표시하는 것은 괜찮다.
만약 데이터가 fresh(staleTime이 지나지 않음)하고, 캐시에도 존재하며. gcTime도 지나지 않았을 때, 이 경우 캐시 된 데이터를 표시하고, 데이터를 refetch 하지 않는다.
데이터가 stale이고 캐시에 존재하며, refetch 트리거가 발생하면, 서버에서 최신 버전의 데이터를 가져올 때까지 캐시 된 데이터를 표시할 것이다.
하지만 데이터가 캐시에 없고, gcTime이 지나 데이터가 삭제됐다면 새로 가져오는 동안 표시할 데이터가 없다. 서버에서 데이터를 가져올 때까지 쿼리는 어떤 데이터도 반환하지 않는다.
데이터가 캐시에 있을 때는, useQuery는 필요조건에 따라 캐시 된 데이터를 반환하고 refetch 할 것이다. 하지만 데이터가 삭제되었거나, 처음부터 없었던 경우에는 서버에서 데이터를 가져올 때까지 표시할 것이 없다.
'프로그래밍 언어 > TanStack-Query' 카테고리의 다른 글
페이지네이션, 프리패칭, Mutation (1) | 2024.02.25 |
---|