[react] Tanstack/react-query v5 사용해보기( feat. useQuery, useMutation, useInfiniteQuery)

rondido·2024년 6월 12일
0

React

목록 보기
40/40

Tanstack/react-query 설정 하기

Tanstack/react-query install

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

권장사항

tanstack query 공식문서에 코딩하는 동안 버그와 불일치를 잡는데 도움이 되도록 ESLint 플러그인 사용을 권장한다.

npm i -D @tanstack/eslint-plugin-query
or
pnpm add -D @tanstack/eslint-plugin-query
or
yarn add -D @tanstack/eslint-plugin-query

프로젝트 적용

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
        <QueryClientProvider client={queryClient}>
           <App />
        </QueryClientProvider>
    </React.StrictMode>,
);

최상단 컴포넌트에 queryClient를 지정해주어야 한다. 나의 경우 main.tsx에 적용

useQuery

const result = useQuery({
  queryKey, // required
  queryFn, // required
  // ...options ex) gcTime, staleTime, select, ...
});

result.data;
result.isLoading;
result.refetch;
// ...
  • useQuery는 v5부터 인자로 단 하나의 객체만 받는다. 그 중에 첫 번째 인자가 queryKey, queryFn이 필수 값이다.
// 실제 사용 예제

const getAllSuperHero = async (): Promise<AxiosResponse<Hero[]>> => {
  return await axios.get("http://localhost:4000/superheroes");
};

const { data, isLoading } = useQuery({
  queryKey: ["super-heroes"],
  queryFn: getAllSuperHero,
});

queryKey

  • useQuery의 queryKey는 배열로 지정해줘야 한다.
useQuery({queryKey:["todo"]})
useQuery({queryKey:["todo",5]})
  • useQuery는 querykey를 기반으로 쿼리 캐싱을 관리하는 것이 핵심
    - 만약, 쿼리가 특정 변수에 의존한다면 배열에다 이어서 줘야 한다. ex: ["todo", todoId, ...]

  • queryKey의 경우 데이터를 고유하게 식별할 수 있다.

queryFn

  • queryFn의 경우 Promise를 반환하는 함수를 넣어야 함.
const Service = async (code: string, state: string) => {
    try {
        const res = await axios.get(`http://localhost:8081/api/v1/profile?code=${code}&state=${state}`);
        return res.data;
    } catch (error) {
        console.error(error);
    }
};

export const useSocialQuery = (code: string, state: string) => {
    return useQuery({
        queryKey: ['social', code, state],
        queryFn: () => Service(code || '', state), // (*)
        enabled: !!code && !!state,
    });
};
  • enabled: boolean
  • enabled는 쿼리가 자동으로 실행되지 않도록 할 때 설정할 수 있다.
  • enabled를 false를 주면 쿼리가 자동 실행되지 않는다.
  • useQuery 반환 값 중 status가 pending 상태로 시작한다.

useQuery 주요 리턴 데이터

const {
  data,
  error,
  status,
  fetchStatus,
  isLoading,
  isFetching,
  isError,
  refetch,
  // ...
} = useQuery({
  queryKey: ["super-heroes"],
  queryFn: getAllSuperHero,
});
  • data: 쿼리 함수가 리턴한 Promise에서 resolved된 데이터
  • error: 쿼리 함수에 오류가 발생한 경우, 쿼리에 대한 오류 객체
  • status: data, 쿼리 결과값에 대한 상태를 표현하는 status는 문자열 형태로 3가지의 값이 존재함.
    - pending: 쿼리 데이터가 없고, 쿼리 시도가 아직 완료되지 않은 상태.
    - { enabled: false } 상태로 쿼리가 호출되면 이 상태로 시작된다.
    - error: 에러 발생했을 때 상태
    - success: 쿼리 함수가 오류 없이 요청 성공하고 데이터를 표시할 준비가 된 상태.
  • fetchStatus: queryFn에 대한 정보를 나타냄
    - fetching: 쿼리가 현재 실행 중인 상태
    • paused: 쿼리를 요청했지만, 잠시 중단된 상태
    • idle: 쿼리가 현재 아무 작업도 수행하지 않는 상태
  • isLoading: 캐싱 된 데이터가 없을 때 즉, 처음 실행된 쿼리일 때 로딩 여부에 따라 true/false로 반환
    - 이는 캐싱 된 데이터가 있다면 로딩 여부에 상관없이 false를 반환
  • isFetching: 캐싱 된 데이터가 있더라도 쿼리가 실행되면 로딩 여부에 따라 true/false로 반환
  • isSuccess : 쿼리 요청이 성공하면 true
  • isError: 쿼리 요청 중에 에러가 발생한 경우 true
  • refetch: 쿼리를 수동으로 다시 가져오는 함수

useInfiniteQuery

 import { useInfiniteQuery } from "@tanstack/react-query";

// useInfiniteQuery의 queryFn의 매개변수는 `pageParam`이라는 프로퍼티를 가질 수 있다.
const fetchColors = async ({
  pageParam,
}: {
  pageParam: number;
}): Promise<AxiosResponse<PaginationColors>> => {
  return await axios.get(`http://localhost:8081/service?page=${pageParam}`);
};

const InfiniteQueries = () => {
 const { data, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteQuery({
        queryKey: ['service', size],
        queryFn: ({ pageParam = 0 }) => service({ pageParam, size }),
        initialPageParam: 0,
        getNextPageParam: (lastPage, allPages) => {
            if (!lastPage.last) {
                return allPages.length;
            }
            return undefined;
        },
    });
  return (
    <div>
      {data?.pages.map((group, idx) => ({
        /* ... */
      }))}
      <div>
        <button disabled={!hasNextPage} onClick={() => fetchNextPage()}>
          LoadMore
        </button>
      </div>
      <div>{isFetching && !isFetchingNextPage ? "Fetching..." : null}</div>
    </div>
  );
};

주요 반환

  • useInfiniteQuery는 반환 값으로 isFectingNextPage, isFetchingPreviousPage, fetchNextPage, hasNextPage 등이 추가적으로 있음.
    - data.pages: 모든 페이지 데이터를 포함하는 배열이다.
    - data.pageParams: 모든 페이지 매개변수를 포함하는 배열이다.
    - fetchNextPage: 다음 페이지를 fetch 할 수 있다.
    - fetchPreviousPage: 이전 페이지를 fetch 할 수 있다.
    - isFetchingNextPage: fetchNextPage 메서드가 다음 페이지를 가져오는 동안 true이다.
    - isFetchingPreviousPage: fetchPreviousPage 메서드가 이전 페이지를 가져오는 동안 true이다.
    - hasNextPage: 가져올 수 있는 다음 페이지가 있을 경우 true이다.
    - hasPreviousPage: 가져올 수 있는 이전 페이지가 있을 경우 true이다.

주요 옵션

  1. initialPageParam: TPageParam
  • initialPageParam을 이용해서 첫 페이지를 가져올 때 사용할 기본 페이지 매개변수이다. 필수값
  1. getNextPageParam: (lastPage,allPages,lastPageParam, allPageParams) => TPageParam | undefined | null
  • getNextPageParam 을 이용해서 페이지를 증가시킬 수 있다. 필수값이다.
    - getNextPageParam의 첫 번째 인자 lastPage는 fetch 해온 가장 최근에 가져온 페이지 목록이다.
    - 두 번째 인자 allPages는 현재까지 가져온 모든 페이지 데이터이다.
    - 세 번째 인자 firstPageParam 는 첫 번째 페이지의 매개변수이다.
    - 네 번째 인자 allPageParams 는 모든 페이지의 매개변수이다.
  • 사용 가능한 다음 페이지가 없음을 표시하려면 undefined 또는 null을 반환하면 된다.
  • getPreviousPageParam도 존재하며, getNextPageParam와 반대의 속성을 갖고 있다

자세한 내용은 여기 참고 바랍니다

profile
개발 옆차기

0개의 댓글