헤더 영역 바로가기 컨텐츠 영역 바로가기 푸터 영역 바로가기
썸네일

React Query에 대해 알아보자!

CODi

2024-10-20 00:40

개요

때는 1달전... 프로젝트를 진행하던 도중 특정 api의 호출을 통해 값의 여부에 따라 순차적으로 api를 호출해야할 일이 있었는데

useEffect의 의존성 배열에 useState의 할당 여부를 기준으로 해결을 하다보니 그에따른 사이드 이펙트가 자꾸 생겨나

해결 방법을 찾아보다 리액트 쿼리를 접하게 되었다......( °ᗝ° ).ᐟ.ᐟ

리액트 쿼리란?

리액트 쿼리는 API로 fetch한 데이터의 로딩 상태, 에러, 받아온 값을 관리해주는 라이브러리 라고 합니다.

또한 가장 중요한 점은 가져온 데이터를 캐싱하여 동일한 데이터에 대해 요청할 경우 메모리에 있는 데이터를 가져오는 기능을 제공합니다!!

초기세팅

다음과 같은 세팅이 필요합니다.

// _app.js

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

import "@/assets/css/main.scss";

const queryClient = new QueryClient();

export default function App({ Component }) {
    return (
        <QueryClientProvider client={queryClient}>
            <Component {...pageProps} />
        </QueryClientProvider>
    );
}

_app.js에서 이렇게 QueryClient를 인스턴스를 생성해 초기화를 하고

QueryClientProvider로 감싸서 전역에서 작동되게 해야 합니다.

어떻게 사용할까

axios를 통한 데이터를 fetch 하는 예시

​const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
  const fetchData = async () => {
      try {
        const response = await axios.get("https://jsonplaceholder.typicode.com/posts");
        setData(response.data);
      } catch (error) {
        setError(error.message);
      } finally {
        setLoading(false);
      }
    };
    fetchData();
}, []);

if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;

위 코드는 간단한 axios를 통한 데이터를 fetch 하는 예시인데

보통 나도 그렇고 try catch 문을 통하여

문제가 생겼을때는 에러 메세지를 표시해주고

데이터를 받아오면 해당 데이터를 useState를 통해 받아온 값을 할당해 사용하는 방식을 취했었다.

그럼 이제 React Query를 통해 fetch 하고 상태에 따라 어떻게 처리하는지 알아보자

axios로 받아온 데이터를 fetch 하는 React Query로 관리하는 예시

​import React from "react";
import { useQuery } from "react-query";
import axios from "axios";

// 데이터를 받아오는 함수
const fetchPosts = async () => {
  const response = await axios.get("https://jsonplaceholder.typicode.com/posts");
  return response.data;
};

// 요소를 반환하는 컴포넌트
const AxiosWithReactQuery = () => {
​  // 여기서 React Query의 useQuery 훅을 통해 각각의 상태를 관리 합니다
  const { data, error, isLoading } = useQuery({
        queryKey: ["posts"],
        queryFn: async () => fetchPosts
  });


  if (isLoading) return <p>Loading...</p>;         // 로딩이 true 일경우 Loading... 보여줌
  if (error) return <p>Error: {error.message}</p>; // 에러가 true 일경우 error에 관한 메세지를 보여줌

​  // 데이터 할당시 요소 반환
  return (
    <div>
      <h1>Data fetched with Axios & React Query</h1>
      <ul>
        {data.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default AxiosWithReactQuery;

전체적인 코드에 주석으로 간간히 적어놓긴 했지만 순서는 이렇다.

1. useQuery의 첫번째 인자에는 키값, 두번째 인자에는 fetch를 실행할 함수

* 키값은 꼭 각각 다르게 설정해주어 캐싱된 데이터를 사용할때 혼선이 생기지 않도록 해야합니다!

const { data, error, isLoading } = useQuery({
        queryKey: ["posts"],
        queryFn: async () => fetchPosts
});

2. 만약 fetch가 실행되면 isLoading이 true로 반환되어집니다.

3-1. 로딩이 끝나고 데이터가 반환되었다면 data에 받아온 데이터가 할당됩니다.

3-2. 로딩이 끝나고 데이터가 반환되지 못했다면 error에 error 메세지가 할당됩니다.

저만의 활용예시​

const { data: songList, isLoading: songListLoading } = useQuery({
        queryKey: ["songList"],
        queryFn: async () => {
            const apiMain = new MainApi();
            return await apiMain.getSongSearchList(utilArtist.getMainArtistList(playlist));
        },
        enabled: !!playlist, // playlist 데이터가 있을 때만 실행
    });

저의 경우 기존에는 useEffect를 통해 의존성 배열의 값이 재할당 될경우 api를 호출 후 useState의 변수명에 할당 하여 사용하는 방식으로 관리를 했었는데

위와 같이 React Query의 enabled 옵션을 통해 playlist라는 변수에 값이 할당되어 있을때 fetch를 할수있도록 하였습니다.

리액트 쿼리 덕분에 스케일이 커지면 커질수록 state, useEffect 등 남발하게 되어 관리가 힘들었는데 덕분에 손쉽게 관리하는 방법을 배웠네용 ୧(๑•̀⌄•́๑)૭

참조​

Tanstack Query​

https://tanstack.com/query/latest

Json PlaceHolder

https://jsonplaceholder.typicode.com/