티스토리 뷰

React Query란?

React application의 데이터를 가져오기(fetching)위한 라이브러리

 

 

기능

  • 캐싱(특정 데이터의 복사본을 저장하여 이후 동일한 데이터의 재접근 속도를 높이는 것)
  • client 데이터와 server 데이터 간의 분리
  • 백그라운드에서 오래된 데이터 업데이트
  • 데이터가 얼마나 오래되었는지 알 수 있음
  • 데이터 업데이트를 가능한 빠르게 반영
  • 페이지네이션 및 데이터 지연 로드와 같은 성능 최적화
  • 서버 상태의 메모리 및 가비지 수집 관리
  • 구조 공유를 사용하여 쿼리 결과를 메모화

 

 

1. 설치

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

 

 

개발자도구: React Query의 모든 내부 동작을 시각화하는 데 도움이 되며 문제가 발생하면 디버깅 시간을 절약할 수 있다.

npm i @tanstack/react-query-devtools

 

 

2. 기본 설정 - QueryClientProvider, QueryClient

//index

import React from "react";
import ReactDOM from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App";
 
// client 생성
const queryClient = new QueryClient();
 
const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
 
root.render(
  <React.StrictMode>
    {/* App에 client 전달 */}
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools initialIsOpen={true} />
    </QueryClientProvider>
  </React.StrictMode>
);

 

 

3. data fetching - useQuery

  • useQuery 공식 문서
  • useQuery는 v5부터 인자로 단 하나의 객체만 받는다. 파라미터 queryKey, queryFn가 필수 값이다.
  • queryKey: data를 식별하도록 하는 고유한 key값을 받음. 데이터를 cache할 때 개발자 도구에서 이 key값이 노출됨.
  • queryFn: 실제 호출하고자 하는 비동기 함수가 들어간다. 필히 Promise를 반환하는 형태여야 한다.

useQuery가 반환하는 객체는 여러 가지가 있는데 그중 자주 사용하는 것들은 아래와 같다.

  • isLoading / isFetching / isSuccess 등 : 현재 Query의 상태
  • data : 응답에 성공한 데이터
  • error : 응답 중 에러가 발생했을 때 반환되는 객체

 

React Query 적용 X

import React from "react";
import { useEffect, useState } from "react";
 
function App() {
  const [loading, setLoading] = useState(true); // 로딩
  const [coins, setCoins] = useState<{ name: string }[]>([]); // 코인 데이터
  useEffect(() => {
    (async () => {
      const json = await (
        await fetch(`https://api.coinpaprika.com/v1/coins`)
      ).json(); // 코인 데이터 비동기 통신
      setCoins(json.slice(0, 100));
      setLoading(false);
    })();
  }, []); // 새로고침 시 데이터를 가져오고 데이터가 준비되면 state에 저장하고 로딩은 false
  return (
    <>
      <h1>리액트 쿼리 실습</h1>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {coins.map((coin) => (
            <li>{coin.name}</li>
          ))}
        </ul>
      )}
    </>
  );
}
 
export default App;

 

 

React Query 적용 O

import React from "react";
import { useQuery } from "@tanstack/react-query"; // useQuery import
 
async function fetchCoins() { // fetcher 함수 생성
  return fetch(`https://api.coinpaprika.com/v1/coins`).then((response) =>
    response.json()
  );
}
 
function App() {
  const { isLoading, data } = useQuery<{ name: string }[]>(
    queryKey: ["allCoins"], // 고유한 querykey
    queryFn: fetchCoins // fetcher 함수
  );
  return (
    <>
      <h1>리액트 쿼리 실습</h1>
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {data?.slice(0, 100).map((coin) => ( // data 렌더링
            <li>{coin.name}</li>
          ))}
        </ul>
      )}
    </>
  );
}
 
export default App;

useQuery Hook을 활용해서 useEffect와 setState 과정을 useQuery를 이용하는 한 줄로 줄일 수 있다.

 

 

4. useQueries

여러 개의 useQuery를 한 번에 실행하고자 하는 경우, 기존의 Promise.all()처럼 묶어서 실행할 수 있도록 도와준다.

const ids = [1,2,3]
const results = useQueries({
  queries: ids.map(id => (
    { queryKey: ['post', id], queryFn: () => fetchPost(id), staleTime: Infinity },
  )),
})
// id를 기반으로 쿼리를 구분
// staleTime: 신선한 상태로 남아 있는 시간

staleTime 과 gcTime 에 대한 설명

 

 

5. useMutation

기본적으로 GET에는 useQuery,

PUT, UPDATE, DELETE에는 useMutation이 사용된다.

 

간단한 예시

// App.tsx
import React from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { updateItem, deleteItem } from './api';

const App: React.FC = () => {
  const queryClient = useQueryClient();

  const updateMutation = useMutation(updateItem, {
    onSuccess: () => {
      // 성공적으로 수정되면, 아이템 목록 쿼리를 무효화하여 최신 상태로 갱신
      queryClient.invalidateQueries(['items']);
    },
  });

  const deleteMutation = useMutation(deleteItem, {
    onSuccess: () => {
      // 성공적으로 삭제되면, 아이템 목록 쿼리를 무효화하여 최신 상태로 갱신
      queryClient.invalidateQueries(['items']);
    },
  });

  return (
    <div>
      <button
        onClick={() => updateMutation.mutate({ itemId: 1, itemData: { title: 'Updated Item' } })}
      >
        Update Item
      </button>
      {updateMutation.isLoading && <p>Updating item...</p>}
      {updateMutation.isError && <p>Error updating item</p>}

      <button onClick={() => deleteMutation.mutate(1)}>
        Delete Item
      </button>
      {deleteMutation.isLoading && <p>Deleting item...</p>}
      {deleteMutation.isError && <p>Error deleting item</p>}
    </div>
  );
};

export default App;



// useMutation: 비동기 요청(여기서는 수정과 삭제 요청)을 수행하고, 그 결과를 관리. 요청 성공 시 'onSuccess' 콜백을 통해 후속 작업을 정의할 수 있다. 이 예제에서는 요청 성공 후 관련 쿼리를 무효화하여 데이터를 최신 상태로 갱신한다.
// 데이터 수정과 삭제 버튼: 사용자가 버튼을 클릭하면 각각 updateMutation.mutate와 deleteMutation.mutate를 호출하여 데이터 수정 또는 삭제 작업을 실행

 

 

6. useInfiniteQuery

무한 스크롤을 구현할 수 있다.

https://tanstack.com/query/latest/docs/framework/react/reference/useInfiniteQuery

https://velog.io/@strongorange/useInfiniteQuery-%EC%99%80-useInfiniteScroll-Hook

velog.io/@leemember/react-infinite-scroller

 

 

 

 

 

참고

https://velog.io/@kandy1002/React-Query-%ED%91%B9-%EC%B0%8D%EC%96%B4%EB%A8%B9%EA%B8%B0

'Programming > React' 카테고리의 다른 글

상태관리와 Zustand  (0) 2024.03.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함