본문 바로가기
🔥React 뽀개기

React Query 왜 씀?

by 짱돌보리 2024. 7. 20.
728x90

리액트 쿼리를 배우기 전에는 그냥 무한스크롤 구현하는데 쓰이는 애인줄 알았다.
근데 찍먹해봤더니 뭐지?? 서버 상태 불러오고, 캐싱하고, 지속적인 업데이트가 가능..?

React Query 도입 이전에는...

서버에서 가져온 데이터를 클라이언트 상태와 함께 관리해야 했기 때문에, 상태 관리 라이브러리(Redux)를 사용해야 하는 경우가 많았다.


리덕스는 상태를 변경하기 위해서는 액션을 생성해야 하고, 이를 처리하기 위한 리듀서를 작성해야 한다. 이 과정에서 각 액션에 대한 타입을 정의하고, 리듀서를 구현하는 코드가 늘어난다. 그래서 간단한 상태 변경에도 많은 코드가 필요하게 되는 경우가 많다. 결국 코드의 양이 늘어나고, 관리해야 할 상태가 많아져서 오히려 버거워지는 결과를 초래했다.


비동기 데이터를 React Component의 State에 보관하게 될 경우 다수의 Component의 Lifecycle에 따라 비동기 데이터가 관리되므로 캐싱 등 최적화를 수행하기 어렵다.
-> 서버상태 + 캐싱 + 지속적 업데이트를 해주는 쌈@뽕한 React Query 두등장

❓React Query

  • React Application에서 서버의 상태를 불러오고, 캐싱하며, 지속적으로 동기화하고 업데이트 하는 작업을 도와주는 라이브러리
  • 우리에게 친숙한 Hook을 사용하여 React Component 내부에서 자연스럽게 서버의 데이터를 사용할 수 있다.

📍React Query가 하는 일

  1. 데이터 페칭
    React Query는 API로부터 데이터를 쉽게 가져온다. useQuery 훅을 사용하여 비동기 요청을 간단하게 설정할 수 있으며, 데이터가 로드되는 과정에서의 상태(로딩, 오류, 데이터)를 자동으로 관리한다.
    -> 복잡한 로직을 작성할 필요 없이 손쉽게 데이터를 요청하고 사용할 수 있다.
  1. 자동 캐싱
    React Query는 가져온 데이터를 자동으로 캐싱한다. 동일한 쿼리를 요청할 경우, 서버에 요청을 보내지 않고 캐시된 데이터를 즉시 반환하여 성능을 향상시킨다.
    -> 불필요한 API 호출을 줄이고, 애플리케이션의 응답 속도를 높일 수 있다.

❓캐시

  • 데이터를 미리 복사해 놓는 임시 장소
  • 보통 저장 공간의 크기는 작지만, 데이터를 가져오는 속도는 빠르다.
  • 자주 사용하는 데이터를 캐시에 저장해 두면, 해당 데이터를 훨씬 빠르게 가져와서 사용할 수 있다.
  • 웹 브라우저는 기본적으로 캐시를 사용해서 속도를 높이고 네트워크 비용을 아낀다.

    사이트에 접속했을 때 받아 온 데이터를 캐시 형태로 저장해서, 사용자가 같은 사이트에 접속하면 서버에 매번 데이터를 다시 요청하는 게 아니라 저장해 놓은 데이터를 유저에게 보여준다.
    ->이렇게 캐시를 사용하는 걸 '캐싱'이라고 한다.
  1. 데이터 동기화
    서버의 데이터가 변경되면 클라이언트에서도 이를 반영해야 한다. React Query는 데이터의 실시간 동기화를 지원한다. 데이터를 업데이트하거나 삭제한 후에는 해당 데이터를 다시 불러오도록 설정할 수 있어, 항상 최신 상태를 유지할 수 있다.
  2. 서버 상태 관리
    React Query는 서버에서 가져온 데이터를 클라이언트 상태와 분리하여 관리할 수 있도록 해준다.
    -> 복잡한 상태 관리 로직 없이도 서버 상태를 효과적으로 관리할 수 있고, 클라이언트 상태와의 충돌을 방지할 수 있다.
  1. 로딩 및 오류 처리
    데이터를 요청하는 동안 로딩 상태를 관리하고, 요청이 실패했을 때의 오류 처리를 간편하게 할 수 있다. isLoading, isError, error와 같은 상태 변수를 제공하여, UI에서 적절한 피드백을 줄 수 있게 도와준다.
  2. 쿼리 무효화 및 리패칭
    React Query는 특정 쿼리를 무효화할 수 있는 기능을 제공해, 데이터가 변경되었을 때 자동으로 리패칭하도록 설정할 수 있다.
    -> 데이터의 일관성을 유지하고, 사용자에게 항상 최신 정보를 제공할 수 있다.
  1. 페이지네이션 및 무한 스크롤
    React Query는 페이지네이션이나 무한 스크롤과 같은 복잡한 데이터 로딩 패턴을 쉽게 구현할 수 있다.
import axios from 'axios';
import {
  QueryClient,
  QueryClientProvider,
  useMutation,
  useQuery,
  useQueryClient,
} from 'react-query';

// React Query는 내부적으로 queryClient를 사용하여
// 각종 상태를 저장하고, 부가 기능을 제공합니다.
const queryClient = new QueryClient();

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

function Menus() {
  const queryClient = useQueryClient();

  // "/menu" API에 Get 요청을 보내 서버의 데이터를 가져옵니다.
  const { data } = useQuery('getMenu', () =>
    axios.get('/menu').then(({ data }) => data),
  );

  // "/menu" API에 Post 요청을 보내 서버에 데이터를 저장합니다.
  const { mutate } = useMutation(
    (suggest) => axios.post('/menu', { suggest }),
    {
      // Post 요청이 성공하면 위 useQuery의 데이터를 초기화합니다.
      // 데이터가 초기화되면 useQuery는 서버의 데이터를 다시 불러옵니다.
      onSuccess: () => queryClient.invalidateQueries('getMenu'),
    },
  );

  return (
    <div>
      <h1> Tomorrow's Lunch Candidates! </h1>
      <ul>
        {data.map((item) => (
          <li key={item.id}> {item.title} </li>
        ))}
      </ul>

      <button
        onClick={() =>
          mutate({
            id: Date.now(),
            title: 'Toowoomba Pasta',
          })
        }
      >
        Suggest Tomorrow's Menu
      </button>
    </div>
  );
}
// 가장 기본적인 형태의 React Query useQuery Hook 사용 예시
const { data } = useQuery(
  queryKey, // 이 Query 요청에 대한 응답 데이터를 캐시할 때 사용할 Unique Key (required)
  fetchFn, // 이 Query 요청을 수행하기 위한 Promise를 Return 하는 함수 (required)
  options, // useQuery에서 사용되는 Option 객체 (optional)
);

참고