2026 年 React Query vs SWR:我实际使用的以及原因

发布: (2026年4月12日 GMT+8 08:04)
4 分钟阅读
原文: Dev.to

Source: Dev.to

(请提供您希望翻译的正文内容,我将为您翻译成简体中文,并保留原始的格式、Markdown 语法以及代码块和链接不变。)

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 的实现通常更人性化。

我实际使用的混合方案

Server Components 用于初始数据(无需库),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 
}

首次渲染时没有加载闪烁,且客户端包体积保持小巧。

决策框架

如果使用 SWR:

  • Next.js 应用(尤其是 App Router)
  • 简单、以读取为主的数据获取
  • 关注 bundle 大小
  • 小团队,降低缓存管理复杂度

如果使用 React Query:

  • 复杂的 mutation 并带有乐观更新
  • 需要手动缓存预填充 / 预取
  • 大量无限滚动
  • 非 Next.js 的 React(框架无关)

选一个并在两个月内决定。

我在 whoffagents.com 提供 SaaS 工具。

0 浏览
Back to Blog

相关文章

阅读更多 »

我打造了自己的绘图工具

引言 Terry Davis 说得有道理。虽然这不是在 2025 年最让人舒适的引用开场,但这个想法仍然令人印象深刻:如果你在不了解的情况下依赖工具……