React-Query

Ahyeon, Jung·2023년 10월 6일
0

React-Query

React 애플리케이션에서 비동기 데이터를 관리하는 방법을 제공하는 라이브러리
캐시를 사용하여 데이터를 저장하므로 API에서 데이터를 한 번 가져온 다음 애플리케이션 전체에서 재사용가능
TenStack Query로 이름 변경됨

  • 복잡한 Action 및 Reducer 없이도 데이터를 가져오고 관리할 수 있는 간단한 API를 제공. Redux-saga와 같은 미들웨어없이 React-query만으로도 처리 가능
  • 캐시를 사용하여 데이터를 저장. 수행해야하는 API 호출 수를 줄여 애플리케이션의 성능을 향상시킬 수 있음
  • 데이터 리패칭 및 리프레시: 데이터의 유효성 검사를 자동으로 처리하고 필요한 경우 데이터를 다시 가져오거나 업데이트할 수 있는 기능을 제공

Queries

데이터를 가져오고 조회하는데 사용

  • 데이터 캐싱: 쿼리 결과는 자동으로 캐싱되어 이전에 가져온 데이터를 재사용 가능
  • 자동 재요청: 일정한 간격으로 또는 수동으로 쿼리를 다시 요청하여 데이터를 업데이트 가능
  • 오류 처리: 쿼리 실행 중 발생한 오류를 쉽게 처리 가능
  • 상태 관리: 데이터 로딩 상태, 오류 상태, 성공 상태 등을 관리
  • 인터셉터: 쿼리 실행 전 후에 인터셉터를 사용하여 데이터를 수정하거나 로깅가능
import { useQuery } from 'react-query';

const { data, isLoading, isError } = useQuery('myData', fetchDataFunction);  // 쿼리명, 쿼리함수, 옵션

useQuery에서 사용하고 싶은 기능들을 구조 분해 할당하여 사용

  • data : 데이터를 가져옴
  • isError : 데이터를 가져올 때 오류 여부
  • isLoading : 데이터를 가져오는 중
  • isFetching : 비동기 쿼리가 해결되지 않았음
  • error : 에러 메시지

옵션
staleTime
cacheTime

  • 데이터가 비활성화된 이후 남아 있는 시간
  • cacheTime이 지나면 캐시의 데이터가 만료됨, 유효 시간의 기본값 5분
  • 만료되면 가비지 컬렉션이 진행

쿼리키호출 => staleTime 안지났는지 확인 => 지났으면 서버에 호출 안지났으면 => 안지났으면 cacheTime 확인 => cacheTime 지났으면 가비지컬렉션이나 0이면 그냥 캐시가 없어서 아무튼 데이터없으니까 서버에 호출 => 안지났으면 (유효하면서) 데이터가 있는거니까 캐시데이터를 보여줌

쿼리키

컴포넌트를 다시 마운트하거나 윈도우를 다시 포커스할 때
useQuery에서 반환되어 수동으로 리페칭을 실행할 때
지정된 간격으로 리페칭을 자동 실행할 때
변이를 생성한 뒤 쿼리를 무효화 할 때
클라이언트의 데이터가 서버의 데이터와 불일치할 때 리페칭 할 경우
쿼리는 게시물 아이디를 포함하기 때문에 쿼리별로 캐시를 남길 수 있다.
각 쿼리에 해당하는 캐시를 가지게 된다.
각 게시물에 대한 쿼리에 라벨을 설정해주면 된다. 바로 쿼리 키에 문자열 대신 배열을 전달하면 가능하다.

const { data, isLoading, isError, error } = useQuery(
    ["comments", post.id], () => fetchComments(post.id)
 );

이처럼 의존성 배열로 취급해서 사용하면 된다. comments를 쿼리키로 지정한 것이다.
그리고 post.id가 업데이트 되면 리액트쿼리가 새 쿼리를 만들고 staleTime과 cacheTime을 갖게 된다.

Prefetching

  • 데이터를 미리 가져와 캐시에 넣음
  • 기본값으로 만료(stale) 상태를 나타냄
  • useQueryClient
import { useQuery, 🌟useQueryClient } from "react-query";

  const queryClient = useQueryClient();

  useEffect(() => {
    // 10페이지에 있다면 미리 데이터를 가져온 필요가 없다.
    if (currentPage < maxPostPage) {
      const nextPage = currentPage + 1;

      queryClient.prefetchQuery(["posts", nextPage], () =>
        fetchPosts(nextPage)
      );
    }
  }, [currentPage, queryClient]);

    const { data, isError, isLoading, error } = useQuery(
    // 배열에 담긴 첫 번째 요소를 쿼리키라고 한다.
    ["posts", currentPage],
    // 이 배열이 바뀌면 함수도 바뀌기 때문에 데이터가 바뀔 수밖에 없다.
    () => fetchPosts(currentPage), // -> 함수의 파라미터값을 currentPage로 함
    {
      staleTime: 2000,
      // 쿼리키가 바껴도 지난 데이터를 유지해서 이전 페이지로 돌아갔을 때 캐시에 해당 데이터가 있도록 해준다.
      keepPreviousData: true,
    }
  );

Mutations

데이터를 변경하거나 수정하기 위해 사용

  • 비동기 작업 실행 및 결과 처리
  • 최적화된 재요청: 뮤테이션 결과에 영향을 미치는 쿼리들을 자동으로 재요청하여 데이터의 일관성을 유지
  • 오류 처리: 뮤테이션 실행 중 발생한 오류를 쉽게 처리가능
  • 상태 관리: 데이터 로딩 상태, 오류 상태, 성공 상태 등을 관리
  • 인터셉터: 뮤테이션 실행 전후에 인터셉터를 사용하여 데이터를 수정하거나 로깅가능
import { useMutation } from 'react-query';

const mutation = useMutation(updateDataFunction);

const handleUpdate = () => {
  mutation.mutate({ newData: 'newData' });
};

useMutation은 실제로, useQuery와 서로 다른 class 객체를 바라봄
useMutation은 쿼리키를 통해 데이터를 보관하지 않음 => 생성, 수정, 삭제 하기 위해서 api 요청을 하고 성공하면 refetch 또는 invalidateQueries를 통해 쿼리키의 데이터를 변경시켜줌

Query Invalidation

데이터가 변경될 때 캐시된 쿼리 결과를 무효화하여 새로운 데이터를 가져오도록 하는 메커니즘
데이터가 변경될 때 연관된 쿼리를 새로고침하거나 업데이트 가능

import { useQueryClient } from 'react-query';

const queryClient = useQueryClient();

const handleDataUpdate = () => {
  // 데이터가 업데이트되면 'myData'라는 쿼리를 무효화하여 다시 요청합니다.
  queryClient.invalidateQueries('myData');
};

fetch와 사용하기

import React from 'react';
import { useQuery, useMutation, QueryClient, QueryClientProvider } from 'react-query';

// API 호출 함수 정의 (가정)
const fetchData = async () => {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) {
    throw new Error('데이터를 가져오지 못했습니다.');
  }
  return response.json();
};

// React Query를 초기화하고 QueryClientProvider로 감싸기
const queryClient = new QueryClient();

function App() {
  // 데이터 가져오기 쿼리
  const { data, isLoading, isError } = useQuery('data', fetchData);

  // 데이터 업데이트 뮤테이션
  const mutation = useMutation(newData => {
    // 서버에 데이터 업데이트 요청 (가정)
    return fetch('https://api.example.com/update', {
      method: 'POST',
      body: JSON.stringify(newData),
    });
  });

  const handleUpdate = () => {
    // 데이터 업데이트 요청 보내기
    mutation.mutateAsync({ someData: 'newData' });
  };

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (isError) {
    return <div>Error fetching data</div>;
  }

  return (
    <div>
      <h1>React Query Example</h1>
      <button onClick={handleUpdate}>데이터 업데이트</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

function Main() {
  return (
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  );
}

export default Main;

axios와 사용하기

import React from 'react';
import axios from 'axios';
import {
  useQuery,
  useMutation,
  QueryClient,
  QueryClientProvider,
} from 'react-query';

// Axios를 사용하여 데이터 가져오기 함수 정의
const fetchData = async () => {
  try {
    const response = await axios.get('https://api.example.com/data');
    return response.data;
  } catch (error) {
    throw new Error('데이터를 가져오지 못했습니다.');
  }
};

// Axios를 사용하여 데이터 업데이트 함수 정의
const updateData = async (newData) => {
  try {
    const response = await axios.post('https://api.example.com/update', newData);
    return response.data;
  } catch (error) {
    throw new Error('데이터 업데이트에 실패했습니다.');
  }
};

// React Query를 초기화하고 QueryClientProvider로 감싸기
const queryClient = new QueryClient();

function App() {
  // 데이터 가져오기 쿼리
  const { data, isLoading, isError } = useQuery('data', fetchData);

  // 데이터 업데이트 뮤테이션
  const mutation = useMutation(updateData);

  const handleUpdate = () => {
    // 데이터 업데이트 요청 보내기
    mutation.mutateAsync({ someData: 'newData' });
  };

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (isError) {
    return <div>Error fetching data</div>;
  }

  return (
    <div>
      <h1>React Query with Axios Example</h1>
      <button onClick={handleUpdate}>데이터 업데이트</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

function Main() {
  return (
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  );
}

export default Main;

Reference

https://tanstack.com/query/latest/docs/react/overview
https://velog.io/@leemember/React-query-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-useInfiniteQuery-%EB%A1%9C-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-react-infinite-scroller

profile
https://a-honey.tistory.com/

0개의 댓글