2026년 React Query vs SWR: 내가 실제로 사용하는 이유와 방법

발행: (2026년 4월 12일 오전 09:04 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

위에 제공된 소스 링크에 포함된 전체 텍스트를 알려주시면, 해당 내용을 한국어로 번역해 드리겠습니다. 코드 블록이나 URL은 그대로 유지하고, 마크다운 형식과 기술 용어는 그대로 보존합니다. 텍스트를 복사해서 붙여넣어 주세요.

30초 답변

SWR – 더 간단한 API, 작은 번들(~4 KB), Vercel에서 제작 – Next.js와 자연스럽게 맞음. 사용 사례의 약 80 %를 커버합니다.

React Query (TanStack Query) – 더 많은 기능, 더 많은 제어, 큰 번들(~13 KB). 복잡하고 데이터가 많은 앱을 위해 설계되었습니다.

  • 데이터 페칭이 보통인 Next.js 앱: SWR
  • 복잡한 뮤테이션, 무한 스크롤, 캐시 시딩: React Query

SWR 실전

import useSWR from 'swr'

const fetcher = (url: string) => fetch(url).then(r => r.json())

export function useUser(id: string) {
  const { data, error, isLoading, mutate } = useSWR(`/api/users/${id}`, fetcher)
  return { user: data, isLoading, isError: !!error, refetch: mutate }
}

뮤테이션

import useSWRMutation from 'swr/mutation'

async function updateUser(url: string, { arg }: { arg: { name: string } }) {
  return fetch(url, { method: 'PATCH', body: JSON.stringify(arg) }).then(r => r.json())
}

export function useUpdateUser(id: string) {
  const { trigger, isMutating } = useSWRMutation(`/api/users/${id}`, updateUser)
  return { updateUser: trigger, isUpdating: isMutating }
}

SWR의 전체 API는 한 오후만에 머릿속에 들어옵니다.

실전 React Query

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

export function useUser(id: string) {
  return useQuery({
    queryKey: ['user', id],
    queryFn: () => fetch(`/api/users/${id}`).then(r => r.json()),
    staleTime: 5 * 60 * 1000,
  })
}

export function useUpdateUser() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ id, data }: { id: string; data: { name: string } }) =>
      fetch(`/api/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }).then(r => r.json()),
    onSuccess: (_, { id }) => {
      queryClient.invalidateQueries({ queryKey: ['user', id] })
    },
    onMutate: async ({ id, data }) => {
      await queryClient.cancelQueries({ queryKey: ['user', id] })
      const previousUser = queryClient.getQueryData(['user', id])
      queryClient.setQueryData(['user', id], (old: any) => ({ ...old, ...data }))
      return { previousUser }
    },
    onError: (_, { id }, context) => {
      queryClient.setQueryData(['user', id], context?.previousUser)
    },
  })
}

더 자세하지만, 필요할 때 제어가 가능합니다.

React Query가 뛰어난 경우

리스트 → 상세 페이지에서 캐시 시드

// 리스트에서 상세 페이지로 이동할 때 추가 네트워크 요청이 없음
queryClient.setQueryData(['user', user.id], user)

종속 쿼리

const { data: user } = useQuery({ queryKey: ['user', userId], queryFn: fetchUser })
const { data: projects } = useQuery({
  queryKey: ['projects', user?.orgId],
  queryFn: () => fetchProjects(user!.orgId),
  enabled: !!user?.orgId,
})

무한 스크롤

const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
  queryKey: ['posts'],
  queryFn: ({ pageParam = 0 }) => fetchPosts({ cursor: pageParam }),
  getNextPageParam: (lastPage) => lastPage.nextCursor,
})

SWR은 useSWRInfinite를 제공하지만, React Query의 버전이 일반적으로 더 사용하기 편리합니다.

실제로 사용하는 하이브리드

초기 데이터는 서버 컴포넌트(라이브러리 필요 없음), 클라이언트‑사이드 실시간 데이터는 SWR 사용:

// Server Component — plain fetch, no library
export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await db.user.findUnique({ where: { id: params.id } })
  return 
}
// Client Component — SWR for live updates
'use client'
import useSWR from 'swr'

export function UserClient({ initialUser }: { initialUser: User }) {
  const { data: user } = useSWR(`/api/users/${initialUser.id}`, fetcher, {
    fallbackData: initialUser, // Hydrate from server, no loading flash
    refreshInterval: 30_000,
  })
  return 
}

첫 렌더링 시 로딩 깜빡임이 없으며, 클라이언트 번들은 작게 유지됩니다.

Decision Framework

SWR을 사용해야 할 경우:

  • Next.js 앱(특히 App Router)
  • 단순하고 읽기 중심의 데이터 페칭
  • 번들 크기가 중요
  • 소규모 팀, 캐시 관리 복잡도 감소

React Query를 사용해야 할 경우:

  • 낙관적 업데이트가 포함된 복잡한 뮤테이션
  • 수동 캐시 시드/프리패치가 필요
  • 무한 스크롤이 많이 사용되는 경우
  • Next.js가 아닌 React(프레임워크에 구애받지 않음)

하나를 선택하고, 시작한 지 두 달이 지나기 전에 확정하세요.

I ship SaaS tools at whoffagents.com.

0 조회
Back to Blog

관련 글

더 보기 »

내가 직접 만든 다이어그램 툴

Introduction 테리 데이비스는 일리가 있었다. 2025년에 가장 편안한 인용구는 아니지만, 그 아이디어는 남는다: 도구를 이해하지 못한 채 의존한다면…