Skip to content

react-query

@tanstack/react-query

@tanstack/react-query(以前叫 react-query)是一个用于 数据获取、缓存、同步、错误处理、后台刷新等功能的强大库,本质上提供了一种 基于缓存的声明式数据获取框架

🧠 核心原理概览

React Query 的核心思想可以概括为:

用声明式的方式管理异步状态,把服务器数据变成前端 state,并自动处理缓存、请求状态、错误、刷新等复杂逻辑。

下面从架构和内部机制深入讲解

✅ 1. 架构核心组件图

text
┌──────────────────────────┐
│      QueryClient         │    ← 全局管理器(缓存池、调度器)
└────────────┬─────────────┘

        ┌────▼────┐
        │ Queries │    ← 每个 query 拥有一个 QueryObserver 管理订阅
        └────┬────┘

      ┌──────▼────────┐
      │ QueryObserver │ ← 监听一个 Query 并推送结果给 useQuery
      └───────────────┘

        ┌────▼────┐
        │ useQuery│ ← Hook 注册 observer 并订阅结果
        └─────────┘

✅ 2. 核心机制解析

🔹 2.1 Query 缓存模型

  • 每个请求都通过一个唯一的 queryKey 标识,如 ['todos', 1]
  • 结果被缓存到 QueryClient 的内部内存中(可配置持久化)
  • 缓存默认保持活跃 5 分钟(staleTime)

🔹 2.2 Observer 订阅机制

  • 每次 useQuery 都注册一个 QueryObserver
  • 多个组件使用同一个 queryKey 会共享 observer,避免重复请求
  • observer 负责监听 query 的状态(loading, error, success)并触发 UI 更新

🔹 2.3 数据获取策略(Fetch Policy)

  • 初次加载:拉取数据 → 缓存 → 通知 UI
  • 缓存命中:可配置 staleTime,避免重复请求
  • 页面聚焦或网络恢复时:自动重新获取(默认开启)
  • 用户触发 refetch:立即重新拉取

🔹 2.4 后台刷新和窗口聚焦自动请求

React Query 使用浏览器事件:

默认行为:

  • 页面重新聚焦:自动 refetch
  • 网络断线后恢复:自动 refetch

(可通过 refetchOnWindowFocus 和 refetchOnReconnect 配置)

✅ 3. 错误重试机制

  • 默认最多重试 3 次
  • 使用指数退避策略(exponential backoff)
  • 用户可自定义 retry, retryDelay,甚至接入 Sentry 日志
ts
useQuery(['user'], fetchUser, {
  retry: 2,
  retryDelay: attemptIndex => attemptIndex * 1000
});

✅ 4. 异步状态自动处理

每个 useQuery 暴露了标准的状态字段

ts
const { data, isLoading, isError, isSuccess, error } = useQuery(...);

这些状态是由 QueryObserver 响应 Query 内部生命周期变化自动推导的,无需自己维护复杂状态。

✅ 5. 与 React 渲染解耦(关键点)

React Query 不是基于 React 状态管理实现的,而是通过 事件订阅系统 + notify batching,避免了不必要的重新渲染。

具体机制:

  • 内部使用 微任务调度(microtask queue) 聚合通知(类似 React batching)
  • 如果多个 observer 依赖同一个 Query,只会触发一次请求

✅ 6. QueryClient 的作用(全局管理器)

  • 保存所有 Query 的缓存状态(Map 存储)
  • 管理 Mutation 请求
  • 提供外部访问接口,如
ts
queryClient.invalidateQueries(['user']) // 手动标记为 stale
queryClient.setQueryData(['user'], newData) // 手动更新缓存

✅ 7. Mutation 和乐观更新(MutationObserver)

  • Mutation 是用于执行 POST/PUT/DELETE 等操作的 hook
  • 默认不缓存结果,但可用 onSuccess 触发 invalidateQueries
  • 支持乐观更新(如购物车、点赞)
ts
const mutation = useMutation(updateTodo, {
  onMutate: async newTodo => {
    await queryClient.cancelQueries(['todos']);
    const previousTodos = queryClient.getQueryData(['todos']);
    queryClient.setQueryData(['todos'], old => [...old, newTodo]);
    return { previousTodos };
  },
  onError: (err, newTodo, context) => {
    queryClient.setQueryData(['todos'], context.previousTodos);
  },
  onSettled: () => {
    queryClient.invalidateQueries(['todos']);
  }
});

✅ 总结:React Query 的底层本质

机制本质
缓存机制queryKeyQuery 对象缓存于 QueryClient
状态管理非 React 状态,使用 observer + 订阅推送机制
请求调度observer 控制 fetch 和状态变更,自动通知 UI
渲染策略内部 batching 和去重,最大限度减少 React 重渲染
错误处理支持同步/异步错误捕获 + 重试 + fallback
拓展能力支持 devtools、持久化、分页、infinite scroll、SWR 模式、乐观更新等