04. React의 다음 지평, 상태 관리 React-Query

Gardener·2024년 2월 20일

Prog_PRJ

목록 보기
4/6

사실 Front-End를 맡아, 나의 장점으로는 페이지를 만드는 것이다. 하지만 단지 페이지만 만들거면 그냥 HTML 기계를 쓰면 되지 않는가? 그렇다! Front의 꽃은 다시 돌고 돌아, Back에서 받아온 데이터에 대한 상태를 관리하는 것이라고 생각하게 되었다. 하지만 이번 십장생 프로젝트에서 사용한 상태 관리 Tool인 React-Query와 Zustand는 나도 아직까지도 이해를 못한 지경이기 때문에, 프로젝트가 끝나고 잠시 여유로운 지금 이에 대한 정리가 필요하다고 느꼈다.

먼저 react-query의 사용 절차에 대해서 이야기해 볼 필요가 있다.

1. 설치

  1. 설치 코드
    npm install @tanstack/react-query
    yarn add @tanstack/react-query
  1. React-Query 설정
    React-Query는 QueryClinet를 통해 관리된다. 이를 통해 캐시, 네트워크 요청 및 기타 설정을 관리
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* 나머지 앱 컴포넌트 */}
    </QueryClientProvider>
  );
}
  1. 데이터 가져오기 함수 생성 - 이 함수는 , 비동기적으로 데이터를 요청하고 응답을 반환
async function fetchPosts() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
}
  1. useQuery 사용하여 데이터 로딩
  • useQuery 훅을 사용하여, Component에서 server 데이터를 요청하고, 로딩 상태, 데이터, 오류 상태를 관리
import { useQuery } from '@tanstack/react-query';

function Posts() {
  const { data, error, isLoading } = useQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts,
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>An error has occurred: {error.message}</div>;

  return (
    <div>
      {data.map(post => (
        <p key={post.id}>{post.title}</p>
      ))}
    </div>
  );
}

위 과정들을 통해서 React-Query는 서버 상태를 비동기적으로 가져오고, 캐싱하고, 동기화하고, 업데이트하는 복잡성을 추상화해준다.

장점
1. 복잡성 감소 : 데이터 캐싱, 패칭과 같은 작업들을 추상화함으로, 로직과 인터페이스에 집중 가능
2. 코드 재사용성 향상 : 비동기 데이터 관리 로직을 라이브러리가 처리하게 하기 때문에 재사용성이 향상 -> 유지보수와 확장성 측면에서 장점
3. 성능 최적화 : 불필요한 네트워크 요청을 줄이고 사용자에게 더 빠른 응답시간 제공
4. 상태 관리의 단순화

-> 이러한 장점들은 결국 개선된 사용자 경험을 불러온다.

예시 코드

마지막으로 예시 코드를 기반으로 한 줄씩 설명을 이어나가본다. 프로젝트 상황에서, 상태코드 테이블을 기반으로 몇가지의 공통 코드들을 불러올 필요가 있었다. 이러한 상황에서, 코드를 불러오는 React-Query 기반 훅이 필요했었다.

import { useQuery } from "@tanstack/react-query";
import { axiosInstance } from "../apis/lib/axios";

const fetchMultipleDetailCodes = async (codeTypes: string[]) => {
  const requests = codeTypes.map((codeType) =>
    axiosInstance.get(`/codes/details/${codeType}`).then(res => res.data.data)
  );
  // 비동기 요청을 병렬로 실행
  return Promise.all(requests);
};

export const useMultipleDetailCodes = (codeTypes: string[]) => {
  return useQuery({
    queryKey: ['detailCodes', ...codeTypes],
    queryFn: () => fetchMultipleDetailCodes(codeTypes),
  });
};

// 사용 예시 구문
// const { data: multipleDetailCodesData} = useMultipleDetailCodes(["KPT", "AnotherType"]);
const fetchMultipleDetailCodes = async (codeTypes: string[]) => {
  const requests = codeTypes.map((codeType) =>
    axiosInstance.get(`/codes/details/${codeType}`).then(res => res.data.data)
  );
  // 비동기 요청을 병렬로 실행
  return Promise.all(requests);
};
  1. codeTypes을 인자로 받아,각 codeType에 대해 서버에서 상세 코드를 비동기적으로 가져옴
  2. axios.get을 사용하여 각 요청의 응답에서 데이터를 추출해서 배열로 반환한다.
  3. 이는 Promise.all을 사용하여 여러 비동기 요청을 병렬로 실행하고, 모든 요청이 완료되면 결과를 배열로 반환한다.
export const useMultipleDetailCodes = (codeTypes: string[]) => {
  return useQuery({
    queryKey: ['detailCodes', ...codeTypes],
    queryFn: () => fetchMultipleDetailCodes(codeTypes),
  });
  1. 이제 codeTypes 배열을 인자로 받아, useQuery 훅을 사용하여 fetchMultipleDetailCodes 함수를 통해 데이터를 가져옴
  2. 반환하는 useQuery는 다양한 값들이 있겠지만 여기서는 queryKey와 queryFn이 있다.
    1) queryKey는 쿼리 결과를 식별하는데 사용되며, 여기서는 detailCodes와 codeTypes의 배열의 값들을 포함
    2) queryFn은 데이터를 가져오는 함수를 지정하며, fMDC함수가 호출되어 인자로 codeTypes을 받는다.
  3. 이 훅은 최종적으로 로딩 상태, 오류 상태 등을 반환하며 컴포넌트에서 이 데이터를 사용하여 UI구성이 가능하다.

정리 (나만의)

내가 개인적으로 생각했을 때 react-query는 Java의 메소드와 같다고 생각을 했음. react-Query와 zustand에 친해지는 것이 이번 프로젝트의 개인적인 목표!

profile
영혼의 정원수

0개의 댓글