본문 바로가기
[Study] 개발 공부/[React] 리액트 공부

[Study] React Query

by 지공A 2025. 7. 23.

이번 새 프로젝트에 합류하게 되면서 말로만 들었던 React Query를 사용하게 되었다. 사실 프로젝트에서 사용하는 것에는 문제가 크게 없었다.

하지만 저번에 손코딩 면접에서 React Query 문제가 나왔을 때, 정확히 답을 적지 못해서 공부를 좀 해야겠다고 생각했다

 

1. React Query란?

React Query는 서버 상태(예: API에서 불러온 데이터)를 관리하기 위한 라이브러리
useState나 useEffect 없이도 데이터 fetching, 캐싱, 갱신, 에러처리 등을 자동으로 해준다

 

데이터 수정 후 useEffect로 다시 패칭하는 방식은 상태 중복과 리패칭 조건 관리의 어려움이 있기 때문에, React Query에서는 invalidateQueries를 통해 필요한 캐시만 무효화하고, 이를 자동으로 refetch하게 만드는 방식이 더 효율적이다

 

2. useQuery 기본 개념

const { data, isLoading, error } = useQuery(['todos'], fetchTodos);
  • ['todos']: 이건 Query Key. 나중에 이 이름으로 캐시 관리함.  캐시를 구분하는 "이름표" 같은 것.
  • fetchTodos: 실제 데이터를 불러오는 함수.
  • data: 가져온 데이터
  • isLoading: 로딩 중 여부
  • error: 에러 발생 여부

 

3. useMutation + useQuery 캐시 최적화 예시

예: 게시글 삭제 후 목록 갱신하기

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

const fetchPosts = async () => {
  const res = await fetch('/api/posts');
  return res.json();
};

const deletePost = async (id) => {
  await fetch(`/api/posts/${id}`, {
    method: 'DELETE',
  });
};

export default function Posts() {
  const queryClient = useQueryClient();
  // 캐시 조작할 수 있는 도구
  // useQuery는 데이터를 가져와서 자동으로 캐싱
  // 여기서 ['posts']는 이 데이터의 키 값
  // 같은 키로 불러오면 네트워크 없이 캐시만 사용

  const { data: posts } = useQuery(['posts'], fetchPosts); 
  // 목록 불러오기
  // useMutation은 POST, DELETE 같은 요청에 사용
  // 버튼 클릭으로 삭제 요청할 수 있게 해준다
  // mutation.mutate(id)를 호출하면 deletePost(id)가 실행
  
  const mutation = useMutation(deletePost, {
    onSuccess: () => {
      // 삭제 성공 시, posts 데이터를 refetch
      // 게시글을 삭제했으면 목록도 다시 불러와야한다
      // invalidateQueries(['posts'])는 React Query에게 전달:
      // “이 키로 캐시된 데이터 오래됐어! 다시 불러와줘!”
      // 이걸 쓰지 않으면 목록이 그대로. 데이터는 삭제됐지만 UI에 반영이 안 된다
      queryClient.invalidateQueries(['posts']);
    },
  });

  return (
    <ul>
      {posts?.map((post) => (
        <li key={post.id}>
          {post.title}
          <button onClick={() => mutation.mutate(post.id)}>삭제</button>
        </li>
      ))}
    </ul>
  );
}