[react] React Query 사용법

Subin Ryu·2024년 11월 3일
0
post-thumbnail

React Query 사용법

  1. 개념
  2. 목적
  3. 원리
  4. 사용하기

개념

  • 클라이언트와 서버 간의 데이터를 효율적으로 관리하기 위해 설계된 라이브러리.
  • 클라이언트 상태(컴포넌트의 로컬 상태)와 달리, 서버 상태는 원격 데이터베이스에서 관리되고 변경될 가능성이 높기 때문에 관리가 복잡해짐.
  • React Query는 이러한 서버 상태를 쉽게 관리하고, 서버와의 동기화 문제를 해결하는 데 초점을 둠

목적

  • 데이터 페칭 간소화: 서버에서 데이터를 가져오는 코드를 간단하게 작성가능.

  • 자동 캐싱 및 갱신: 데이터를 캐싱하고, 필요에 따라 최신 상태로 자동 갱신.

  • 효율적인 상태 관리: 로딩, 에러, 성공 상태 관리와 같은 반복 작업을 줄이고, 로직을 더 직관적으로 작성할 수 있음.

  • 자동화된 리페칭: 데이터의 유효 기간 설정과 백그라운드 리페칭을 통해 최신 상태를 유지.

  • 전역 데이터 동기화: 같은 데이터를 여러 컴포넌트에서 공유할 때 데이터 동기화를 쉽게 할 수 있음.

원리

  • 캐싱, 백그라운드 리페칭, 데이터 유효성 검사 등의 기능을 통해 서버 데이터를 효율적으로 관리.

  • 캐싱: 데이터를 캐시하여, 동일한 데이터를 여러 컴포넌트에서 사용할 때 서버에 중복 요청을 보내지 않도록 함.
    캐시된 데이터는 설정한 유효 기간이 지나면 자동으로 갱신됨.(gcTime)

  • 쿼리 키(Query Key): 각 데이터 요청에 고유한 쿼리 키를 부여하여 React Query가 요청을 식별하고, 캐시에 저장하거나 갱신 시 사용하는 기준으로 함.

  • 백그라운드 리페칭: 데이터가 오래되거나 유효 기간이 지난 경우, 백그라운드에서 자동으로 서버와 동기화하여 최신 데이터를 유지함.(staleTime)

  • 옵션 기반 유연성: staleTime, gcTime, retry 등의 다양한 옵션을 통해 데이터 유효성 및 갱신 주기를 조정할 수 있어, 특정 데이터의 필요에 맞게 동작을 세부 조정가능.

사용하기

  1. 설치

    npm i @tanstack/react-query
  2. React Query Provider 설정: React Query의 기능을 사용하려면 최상위 컴포넌트에 QueryClientProvider를 추가해야 함

    index.js

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

const queryClient = new QueryClient();

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>
);
  1. Devtools 설치
npm i @tanstack/react-query-devtools

inedex.js

import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

const queryClient = new QueryClient();
root.render(
  <QueryClientProvider client={queryClient}>
    <App />
    {/* initialIsOpen는 devtools을 프로젝트시작할때 연상태로 시작할지, buttonPosition는 devtools 위치정해주기 */}
    <ReactQueryDevtools initialIsOpen={false} buttonPosition="bottom-left" />
  </QueryClientProvider>
);
  1. Json-server 사용하기 - 서버가 필요함으로
npx json-server db.json
  1. useQuery로 데이터 패칭하기: useQuery 훅을 사용하여 데이터를 가져올 수 있음.
  • useQuery의 필수 인자
    1) queryKey
    • 쿼리의 고유한 식별자 역할.
    • React QueryqueryKey를 통해 쿼리를 캐싱하고, 동일한 데이터를 재사용할지 여부를 판단.
    • 일반적으로 문자열 배열로 사용됩니다(예: ['posts']), 또는 고유 식별이 필요할 경우 여러 요소가 포함된 배열(예: ['posts', postId])로 정의할 수도 있음.
    2) queryFn
    • 데이터 패칭 함수
    • 데이터를 가져오는 함수로, 보통 API 호출을 수행
    • 비동기 함수여야 하며, Promise를 반환
    • queryFn이 반환하는 데이터를 useQuerydata 속성으로 제공
  • 추가 옵션 인자(api 호출 디테일 설정)
import { useQuery } from '@tanstack/react-query';
import React from 'react';
import axios from 'axios';

const ReactQueryPage = () => {
  const fetchPost = () => {
    return axios.get('http://localhost:3000/posts');
  };

  // useQuery는 컴포넌트가 시작할 때 실행됨(mount시)
  const { data, isLoading, isError, error, refetch } = useQuery({
    // 각각의 api 호출에 이름을 지어줌(unique 해야함)
    queryKey: ['posts'],
    //호출하고 싶은 api 함수
    queryFn: fetchPost,
    // api 로드 실패시 재시도 횟수 default 3번 더
    retry: 1,
    // 필요한 데이터만 추출
    select: (data) => {
      return data.data;
    },
  });

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>{error.message}</div>;
  return (
    <div>
      {data?.map((item) => (
        <div>{item.title}</div>
      ))}
      <button onClick={refetch}>pass</button>
    </div>
  );
};

export default ReactQueryPage;

data 객체 형태

Devtools

Fresh 상태일때는 cache에서 데이터를 들고 옴
staleTime은 거의 변하지 않는 데이터에 적절하게 사용해야 함.

  • *커스텀 훅
    : 비즈니스 로직과 UI를 구분하는 게 중요 -> useQuery부분 훅으로 분리

    1. ReactQueryPage.js
  import React from 'react';
  import { usePostQuery } from '../hooks/usePosts';

  const ReactQueryPage = () => {
    // 어느 컴포넌트에서든 쉽게 불러 올 수 있음
  const { data, isLoading, isError, error, refetch } = usePostQuery();


    if (isLoading) return <div>Loading...</div>;
    if (isError) return <div>{error.message}</div>;
    return (
      <div>
        { {data?.map((item) => (
          <div>{item.title}</div>
        ))} }
      </div>
    );
  };
  export default ReactQueryPage;
    1. usePosts.js 커스텀훅
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

const fetchPost = () => {
  return axios.get(`http://localhost:3000/posts/${postId}`);
};

export const usePostQuery = () => {
  return useQuery({
    // 각각의 api 호출에 이름을 지어줌(unique 해야함)
    queryKey: ['posts', postId],
    //호출하고 싶은 api 함수
    queryFn:fetchPost(),
    // api 로드 실패시 재시도 횟수 default 3번 더
    retry: 1,
    // 필요한 데이터만 추출
    select: (data) => {
      return data.data;
    },
  });
};
  • 쿼리 여러개 호출
    병렬적으로 비동기 실행!
    DetialPage.js
import { useQueries } from '@tanstack/react-query';
import axios from 'axios';
import React from 'react';

const DetialPage = () => {
  const ids = [1, 2, 3, 4];
  const fetchPostDetail = (id) => {
    return axios.get(`http://localhost:3000/posts/${id}`);
  };

  const results = useQueries({
    queries: ids.map((id) => {
      return {
        queryKey: ['posts', 'id'],
        queryFn: () => fetchPostDetail(id),
      };
    }),
    // 필드 정해서 원하는 데이터 추출해서 넣을 수 있음
    combine: (results) => {
      return { data1: results.map((result) => result.data.data) };
    },
  });
  return <div>DetialPage</div>;
};

export default DetialPage;
  • useQuery로 여러개 호출해도 가능
profile
개발블로그입니다.

0개의 댓글