Frontend/React

React Query 란 ?

취업하고싶다! 2023. 12. 31. 18:51

패스트캠퍼스 x 야놀자 웹 프론트엔드 부트캠프 파이널 프로젝트를 준비중인데, 팀원 중 한 분이 상태관리로 React Query를 쓰는 것이 어떻겠냐고 하셔서 React Query가 무엇인지 공부하고 정리하고자 한다.

 

React Query 란 ?

공식 문서에 따르면, 아주 강력한 비동기 상태를 관리하는 툴이라고 한다.

그럼 이 상태가 무엇인지 알아보자.

 

 

상태(State) 란 ?

주어진 시간에 대한 시스템을 표현한 것

문자열, 배열, 객체 등 다양한 형태로 Application에 저장된 데이터

 

이를 프론트 개발자 입장에서 본다면,

페이지가 로드되거나 렌더링된 이후 사용자가 수행한 모든 동작에 대한 결과라 할 수 있다. 

 

사용자가 액션을 취하면 그 액션에 따라 상태(state)가 바뀔거고 변경된 상태에 따라 View(웹페이지 화면)이 바뀜. 그러면 사용자가 바뀐 View를 보고 또 액션을 취함. 이 사이클을 관리하는 것이 State Management 임.

 

 

 

React Query 외의 다른 상태 관리 라이브러리는 ? 

Redux, Zustand, Recoil 등이 있지만 리액트 쿼리가 이것들과 무엇이 다른지 알아보자.

공식문서에 따르면, 위 사진의 다른 상태 관리 라이브러리들은 비동기 및 서버 상태 관리에는 적합하지 않다.

 

그러면 이제 또 비동기 및 서버 상태란 무엇인지에 대한 의문이 들텐데, 무엇인지 알아보자.

 

 

서버 상태(server state) 란 ?

클라이언트에서 제어하지 않거나 소유하지 않은 위치에서 관리됨

fetching 및 updating 을 위해 비동기 API 필요

소유권이 공유되므로 사용자가 모르는 사이에 다른 사용자가 변경할 수 있음

주의하지 않으면 어플리케이션에서 'out of date' 상태가 될 수 있음

 

서버 상태들을 관리하다보면 필연적으로 발생하는 문제들이 있음

  • 캐싱
  • 같은 데이터 요청 중복 제거
  • 언제 out of date 되는지 알아내기
  • out of date 된 데이터 백그라운드에서 업데이트
  • 최대한 빠르게 업데이트 반영
  • pagination, lazy loading 등 성능 최적화
  • 서버 상태의 메모리, garbage collection 관리
  • structural sharing 으로 쿼리 결과 memoizing

이러한 여러 문제들에 대해, 리액트 쿼리 공식 문서에서는 '리액트 쿼리는 서버 상태를 관리하기 위한 가장 좋은 라이브러리 중 하나다' 라고 소개하고 있다.

 

 

리액트 쿼리와 캐싱

stale-while-revalidate 란 ?

react query 에 사용되는 캐싱 매커니즘

즉, 캐싱된 데이터를 사용자에게 제공하면서 비동기적으로 콘텐츠를 서버에 revalidate 

 

 

그림으로 상세하게 살펴보자.

캐싱되지 않았을 경우 서버에 요청을 보내면, 개발자가 미리 설정한 로딩 스피거나 나오거나 아무것도 안나올 것이고 그 이후에,

 

패칭이 끝나면 새로운 데이터로 업데이트가 될 것이다.

 

근데, 만약에 리액트 쿼리를 써서 캐싱이 된 데이터를 쓸 겅우, 

fecthing 을 하면 로딩 스피너가 나오지 않고 미리 캐싱된 데이터를 사용자에게 보여주고 fetching이 끝나면 새로운 데이터를 보여준다.

즉, 오래된 데이터가 데이터가 없는 것 보다는 낫다는 것이다.

 

 

Query 상태 흐름도

먼저 fetching 을 하면 데이터가 fresh 된 상태로 바뀜

그 이후에 staleTime에 따라, staleTime이 지나면 stale 상태로 바뀜

기본값은 0이고 예를 들어 3초라고 설정하면, 3초 후에 stale 상태가 됨(상한 상태, 오래된 상태)

 

그리고 이 상태에서 다시 데이터를 fetching 해야 할 경우 다시 fetching을 하고 fresh 상태가 됨

그렇지 않고 화면에서 사용하지 않을 경우 inactive 상태로 변경이 됨

inactive 상태에서도 또 다른 타이머(gcTime- 가비지컬렉터 타임) 가 들어가는데, 기본값은 5분으로 설정되어 있음

예시로 3초라고 생각하면, 3초를 기다리고 화면에서 사용하지 않는다라고 판단하게 되면 캐시에 delete 됨

 

 

React Query 사용법

QueryClient 란 ?

모든 쿼리에 대한 상태 및 캐시를 가지고 있는 클래스

react query 를 사용하기 위해서는 필수적으로 생성해줘야 함

 

예시처럼, queryClient 를 선언하고 QueryClient 의 props 로 queryClient를 전달해주면 하위 컴포넌트(Todos) 에서 QueryClient 에 접근할 수 있다.

 

QueryClient 에서는 전역적으로 옵션을 선택할 수 있는데, defaultOption 을 보면 queriesmutations 에 대한 옵션을 설정해주는 것을 알 수 있다.

 

Queries 란 ?

비동기적 데이터의 선언적 의존성으로, 쉽게 말하면 서버에서 데이터를 받아올 때 사용하는 기능이다.

 

useQuery 를 사용함으로써 query 를 사용할 수 있다.

주의할 점은, v5 부터는 인자를 사진과 같이 객체 형태로 전달해야 한다는 것이다.

 

인자로 전달되는 key 와 queryFn 옵션에는 어떤 값이 들어가는지 알아보자.

 

queryKey 란 ?

캐시를 관리하기 위한 키값으로, 배열 형태로 사용 

리액트 쿼리에서는 쿼리 키를 string 형태로 해쉬해 key 와 data 를 mapping 시켜 관리 

 

queryFn 란 ?

promise 를 반환하는 함수(fetch, axios 등)

data 를 resolve 하고 error 를 던짐

 

queryKey, queryFn 외의 옵션

 

 

Queries 가 최종적으로 반환하는 값

데이터와 에러를 반환함

 

 

Mutations 란 ? 

Mutations 는 CRUD 중 RUD 에 해당하는 기능으로 서버의 데이터를 수정할 때 사용하는 기능

 

useMutation 함수를 선언함으로써 Mutations 기능을 사용할 수 있음

Queries 와는 달리, 필수값에 key 가 들어가지 않음

 

 

Mutations 옵션

 

 

Mutations 가 최종적으로 반환하는 값

 

 

 

useSuspenseQuery 란 ? 

react의 Suspense for Data Fetching API 를 사용하기 위한 hook

(Suspense : 데이터를 불러오는 동안 fallback UI 를 대신 보여주는 기능)

 

 

useQuery 는 어떻게 데이터를 저장할까 ?

context 를 사용해 전역적으로 데이터 사용 가능

context API 를 사용해 useClientProvider 하위에 써놓은 Query 들을 서로 공유해서 사용할 수 있음

  

컴포넌트에서 useQuery 가 실행되면 생성된 Query 인스턴스와 함께 key 값으로 mapping 시키는 과정을 거침

그리고 fetch 된 데이터를 query 객체 내부에 저장함으로써 캐시를 관리함

 

context 를 사용했기 때문에 저장된 캐시값은 다른 컴포넌트에서도 사용 가능하게 됨