Javascript/React

[React Query] useQuery

  • -
728x90

 

React Query란?

React Query는 데이터 Fetching, 캐싱, 동기화 서버 쪽 데이터 업데이트 등을 쉽게 만들어주는 React 라이브러리 이다.

Redux, Recoil, Mobx 등의 상태관리 라이브러리들로도 충분히 가능하지만, 클라이언트 쪽의 데이터들을 관리하는데에 있어서 적합할 수는 있어도 서버 쪽의 데이터들을 관리하기에는 여러가지 처리등이 필요한 점들이 있어서 등장하게 되었다.

예를 들어서, 같은 페이지를 바라보고 있는 관리자가 있을 때, 한 관리자가 유저의 데이터를 변경하면, 다른 관리자도 그 유저의 변경된 데이터를 확인할 수 있어야 한다.

설치

최근 v4로 업그레이드 되면서 yarn add react-query or npm i react-query 이었던 설치 command가 아래처럼 바뀌었다.

yarn add @tanstack/react-query
# or
npm i @tanstack/react-query

사용법

QueryClientProvider 설정

ReactQuery는 캐시를 관리하기 위해 QueryClient 인스턴스를 사용한다. 컴포넌트가 useQuery 훅 안에서 QueryClient 인스턴스에 접근할 수 있도록 QueryClientProvider 를 컴포넌트 트리 상위에 추가해줘야 한다.

index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <React.StrictMode>
			...
      <QueryClientProvider client={queryClient}>
				...
        <App />
				...
      </QueryClientProvider>
			...
  </React.StrictMode>
);

React Query를 통해 관리하는 쿼리 데이터는 라이프사이클에따라 fetchig, fresh, stale, inactive, delete 상태를 가진다.

  • fetching : 요청중인 쿼리
  • fresh : 만료되지 않은 쿼리, 컴포넌트가 마운트, 업데이트되어도 데이터를 다시 요청하지 않는다.
  • stale : 만료된 쿼리, 컴포넌트가 마운트, 업데이트되면 데이터를 다시 요청한다.
  • inactive : 사용하지 않는 쿼리, 일정 시간이 지나면 가비지 컬렉터가 캐시에서 제거한다.
  • delete - 가비지 컬렉터에 의해 캐시에서 제거된 쿼리

important defaults

다음은 React Query에서 제공하는 API의 기본이 되는 설정이다.

  • useQuery(그리고 useInfiniteQuery)로 가져온 데이터는 기본적으로 stale 상태가 된다.
    • staleTime 옵션으로 데이터가 stale 상태로 바뀌는데 걸리는 시간을 늘릴 수 있다.
  • stale 쿼리는 다음 경우에 백그라운드에서 다시 가져온다
    • 새로운 쿼리 인스턴스가 마운트되었을 때
    • 브라우저 윈도우가 다시 포커스되었을 때
    • 네트워크가 다시 연결되었을 때
    • refetchInterval 옵션이 있을 때
  • 활성화된 useQuery, useInfiniteQuery 인스턴스가 없는 쿼리 결과는 “inactive” 라벨이 붙으며 다음에 사용될 때까지 남아있는다.
    • inactive 쿼리는 300초(5분) 후에 메모리에서 해제된다.
  • 백그라운드에서 3회 이상 실패한 쿼리는 에러 처리된다.
    • retry 옵션으로 쿼리 함수에서 오류 발생시 재시도할 횟수, retryDelay 옵션으로 재시도 대기 시간을 설정
  • 쿼리 결과는 memoization을 위해 structural sharing을 사용하며 데이터 reference는 변경되지 않는다
    • immutable.js에서 사용하는 기술.(참고할만한 글)
    • 99.9% 케이스에서는 이 옵션을 끌 필요가 없음.
    • structural sharing은 JSON 호환 데이터에만 적용되며, 다른 타입의 쿼리 결과는 항상 변경되었다고 판단한다.

useQuery

서버에서 데이터를 가져오고 캐싱하는데 사용하는 훅이다.

const { data, isLoading , ... } = useQuery(queryKey, queryFunction, options);
  • queryKey
    • v3에서는 문자열과 배열을 넣을 수 있고 v4부터는 배열만 넣을 수 있다.
    • react-query는 이 key 값에 따라 캐싱 처리를 별도로 관리한다. 따라서 key값들은 중복되지 않고 고유한 값이어야한다.
    • 문자열은 단순히 id로서 작용한다.
    • 배열은 문자열과, 객체 필드값을 가질 수 있다.
// v3
useQuery('key', ...);

// v4
useQuery(['key'], ...);

// 다른 키로 취급
useQuery(['key1', 1], ... );
useQuery(['key1', 2], ... );

// 객체 필드의 값이 달라도 다른 키로 취급
useQuery(['key1', { checked: true }], ...)
useQuery(['key1', { checked: false }], ...)

// 객체 필드의 순서가 달라도 내용이 같으면 같은 키로 취급
useQuery(['key1', { checked: true, name:'hi' }], ...)
useQuery(['key1', { name:'hi', checked: true }], ...)
  • return 값 ( useQuery의 return값은 매우 많다. 자세한 내용은 공식문서 참조 )
    • data : 쿼리 함수가 반환한 Promise에서 resolve된 데이터
    • state : 상태가 반환할 수 있는 값은 ‘loading’, ‘error’, ‘success’ 가 있다. 조건문으로 쿼리의 상태를 확인 할 수 있다. (if(state === ‘loading’) 아래 반환 값들로 편하게 사용할 수 있다.
      • isLoading : 저장된 캐시가 없는 상태에서 데이터를 요청중 여부
      • isError : 쿼리 시도에서 오류 발생 여부
      • isSuccess : 쿼리가 오류 없이 응답을 받았고 데이터를 표시할 준비가 되었는지 여부
    • isFetching : 캐시가 있거나 없거나 데이터가 요청중인지 아닌지 boolean 값
    • refetch : 쿼리를 수동으로 다시 fetch하는 함수이다.
  • options
    • cacheTime : 캐시 데이터가 메모리에서 유지될 시간이다. 기본값은 5분이며 설정한 시간을 초과하면 메모리에서 제거된다. Infinity 로 설정하면 쿼리 데이터는 캐시에서 제거되지 않는다.
    • staleTime : 쿼리 데이터가 fresh 에서 stale로 전환되는데 걸리는 시간이다. 기본값은 0이며 Infinity 로 설정하면 쿼리 데이터는 직접 캐시를 무효화할 때까지 fresh 상태로 유지된다.
    • enabled : false 값이 전달되면 쿼리가 비활성화 된다.
      • 데이터 요청에 사용할 파라미터가 유효한 값일 때만 true 를 할당하는 식으로 활용할 수 있다.
    • onSuccess : 쿼리 함수가 성공적으로 데이터를 가져왔을 때 호출되는 함수
    • onError : 쿼리 함수에서 오류가 발생했을때 호출되는 함수
    • onSettled : 쿼라 함수의 성공, 실패 여부와 관계없이 실행되는 함수
    • keepPreviousData : 쿼리 키가 변경되어서 새로운 데이터를 요청하는 동안에도 마지막 데이터 값을 유지한다.
      • 페이지네이션을 구현할 때 유용하다. 캐시되지 않은 페이지를 가져올 때 화면에서 목록이 사라지는 깜빡임 현상을 방지할 수 있다.
      • isPreviousData 값으로 현재의 쿼리 키에 해당하는 값인지 확인할 수 있다.
    • initialData : 캐시된 데이터가 없을때 표시할 초기값. placeholder로 전달한 데이터와 달리 캐싱이 된다. 브라우저 로컬 스토리지에 저장해둔 값으로 데이터를 초기화 할 때 사용할 수 있다.
    • refetchOnWindowFocus : 윈도우가 다시 포커스되었을 때 데이터를 호출할 것인지 여부, 기본값은 ture 이므로 필요없으면 false 를 주면 된다.

 

Example

import React from "react";
import { QueryClient, useMutation, useQuery } from "@tanstack/react-query";

const getPosts = () => {
  // api Post 목록 get 요청
  return;
};

const postPost = () => {
  // api Post 생성(post) 요청
  return;
};

const Test = () => {
  // Access the client
  const queryClient = new QueryClient();

  // Queries
  const query = useQuery(["posts"], getPosts, {});

  // Mutations
  const mutation = useMutation(postPost, {
    onSuccess: () => {
      // Invalidate and refetch
      queryClient.invalidateQueries(["posts"]);
    },
  });

  return (
    <div>
      <ul>
        {query.data.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>

      <button
        type='button'
        onClick={()=>{
          mutation.mutate({id: 999, title:'제목'})
        }}
      >
        post 추가
      </button>
    </div>
  );
};

export default Test;

 

useMutation은 다음 포스트에서 ...

728x90
300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.