React Query 기본 개념


프론트엔드 개발을 진행하면 서버의 데이터를 API 를 통해 가져온 다음 화면에 보여주는 data fetching 작업을 거의 밥 먹듯이 하는데 이런 경우 API 요청에 대한 상태 값(성공, 실패 등)에 대한 케이스들을 custom hook 을 통해 관리한다. custom hook 을 통해서 재활용이 가능하지만 프로젝트를 시작할 때마다 생성을 해줘야되기 때문에 은근히 번거롭다. 또한 클라이언트 단에서 서버 데이터를 렌더링하는 경우 Redux 나 Recoil 등의 전역 상태 관리 라이브러리를 한번 거친 뒤에 렌더링이 진행되기 때문에 클라이언트 단에서만 사용하는 Client State 와 서버에서 가져온 데이터인 Server State 의 구분이 명확하지 않다는 단점도 존재한다.
이를 React Query 를 통해 보완할 수 있다.
 
  • Client State: 클라이언트 환경에서만 사용되는 상태 값 (다크모드, 모달 생성 여부, input value 값 등)
  • Server State: 서버에서 가져와서 사용되는 상태 값 (post 리스트, 사용자 정보 등)
 
codesandbox 를 통해 예제를 확인할 수 있다.

useQuery

데이터를 정보를 가져오는 경우 (GET) 사용한다.
  • queryKey : 쿼리의 고유 키, 캐싱 등에 사용된다.
  • queryFn : 비동기 처리를 하는 함수 (axios, fetch 사용)
 
queryKeyqueryFn 를 객체 형태가 아닌 형태로 적용하는 방식도 사용할 수 있다.
같은 endpoint 를 여러개 호출하는 경우 queryKey 를 같게 설정하면 api 가 한 번만 호출되고 다르게 설정하면 api 가 여러 번 호출된다. (브라우저의 개발 탭에서 확인 가능)
 
  • queryKey 를 같게 설정한 경우
notion image
  • queryKey 를 다르게 설정한 경우
notion image
또한 endpoint 가 다르더라도 queryKey 가 같은 경우, 먼저 실행되는 쿼리만 호출된다.
notion image

enabled

default: true
useQuery 를 여러 개 사용하는 경우 동기적으로 호출할 수 있도록 해준다.
useTodosQuery 의 data 값이 있는 경우 (useTodos2Query 의 enabledtrue 인 경우) useTodos2Query 가 실행된다.

refetchOnMount

default: false
값이 always 인 경우 컴포넌트가 마운트 될 때마다 쿼리가 refetch 된다.
부모 컴포넌트인 Parent 컴포넌트와 useQuery 를 사용하는 자식 컴포넌트 Children 컴포넌트가 있는 환경에서 Parent 컴포넌트의 useState 를 통해 Children 컴포넌트를 조건부 렌더링하는 경우 refetchOnMount 값이 always 이면 Query 컴포넌트가 렌더링될 때마다 쿼리가 refetching 된다.

refetchInterval

일정 시간마다 refetch 를 해주는 설정이다. 일정 시간마다 최신 데이터를 적용해주는 기능에 사용하면 유용할 것 같다. (스포츠 문자 중계 등)

refetchOnWindowFocus

default : true
브라우저가 unfocus(탭을 변경하거나 최소화하는 등의 상태 변경이 있는 경우) 된 상태에서 focus 를 하면 해당 페이지에서 호출되는 쿼리를 refetching 해준다.

refetchIntervalInBackground

refetchInterval 옵션과 함께 쓰이며 브라우저에 focus 가 되어있지 않아도 refetchInterval 에 적용된 시간마다 refetching 된다.

refetchOnReconnect

default: true
네트워크 접속이 불가능한 상태에서 다시 접속하는 경우 refetch(api 호출) 여부를 설정할 수 있다.
  • false : refetch 를 하지 않는다.
  • true : 데이터가 오래된 경우(staleTime 옵션값을 통해 해당 시간이 지난 경우) 에만 refetch 를 진행한다.
    • stale: 사전적 의미 → 신선하지 않음, 캐싱 상태의 값을 의미
  • always : 네트워크에 접속될 때마다 refetch 를 진행한다.

select

useQuery 를 통해 가져온 데이터를 가공시킬 수 있다.
여러 가지 조건에 맞는 형태로도 가공이 가능하다.

useQueries

여러 개의 쿼리를 가져오는 경우 사용된다.
useQuery() 를 여러 번 사용해도 기능이 동작하지만 각각의 useQuery() 에 성공, 실패 등의 상태에 따른 예외 처리를 각각 적용해야 되는 번거로움이 발생하기 때문에 useQueries() 를 통해 한 번에 처리하여 더욱 깔끔하게 적용할 수 있다.
useQueries() 은 배열을 반환하기 때문에 every() 를 통해 모든 쿼리가 성공인 경우에만 console.log 를 실행시켰다.

useInfiniteQuery

무한 스크롤을 통해 서버 데이터를 렌더링하는 경우 사용된다.

useMutation

  • mutationFn : Promise 를 반환하는 함수 (api 요청 함수)
  • onSuccess : mutation 이 성공하는 경우 실행되는 함수
  • onError: mutation 이 실패하는 경우 실행되는 함수
  • onSettled: 상태와 관계없이 실행되는 함수 (try..catch 문의 finally 같은)
 
useMutation 뿐만 아니라 myMutation 에서도 상태 값에 따라 실행되는 함수들을 설정할 수 있다.
  • variables: mutationFn 의 매개변수로 전달되는 값

invalidateQueries

버튼을 클릭하면 POST:(/todo) 를 통해 데이터를 추가하는 함수 addTodos 가 있고 아래에는 GET:(/todos) 을 통해 가져온 데이터의 리스트를 표시하는 페이지가 있다고 가정해보자.
이 상황에서 addTodos 함수를 실행하는 버튼을 클릭하면 데이터는 추가되지만, 하단의 리스트는 react-query 의 cache 로 인해 새로운 데이터가 추가되어도 최신화가 되지 않는 이슈가 발생한다.
이런 경우 invalidateQueries 를 통해 queryKey 유효성(캐시 데이터) 을 제거하여 최신 데이터를 적용할 수 있다.
myMutation.mutate 을 통해 전달받은 값을 적용시키는 경우 setQueryData 를 사용한다.
 

 
출처