mcpField
W
web-server-state-react-query

web-server-state-react-query

github.com/agents-inc开发2675 次安装2 天前更新
代码仓库

关于 web-server-state-react-query

面向在 React 应用中管理服务器数据的 React Query 实践指南,涵盖缓存行为、类型化查询选项、错误、变更和分页。适用于由 API 架构生成客户端或手写查询的场景。

主要功能

  1. 01生成类型化查询选项
  2. 02查询键与缓存配置
  3. 03集中处理查询和变更错误
  4. 04变更操作与缓存失效
  5. 05无限查询与游标分页

适用场景

  1. 01根据 API 架构生成查询
  2. 02管理数据新鲜度与缓存清理
  3. 03跨组件处理错误
  4. 04构建分页数据视图

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/agents-inc/skills --skill web-server-state-react-query

安装后在 Claude Code 中输入/web-server-state-react-query确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.yaml
reference.md
examples/
core.md
error-handling.md
infinite-queries.md
mutations.md
suspense.md

详细介绍

React Query 模式

快速指南: React Query 管理服务端缓存——获取了哪些数据、数据会保持新鲜多久,以及何时被清除。每个条目都由其 queryKey 标识,而 staleTime 和 gcTime 是两个独立的计时器,并非同一个。v5 从 useQuery 中移除了 onError/onSuccess/onSettled,因此错误副作用应放在组件中,或放在共享的 QueryCache 上。

详细资源:


适用路径

  • API 有可用于生成的 Schema — 从中生成类型、服务函数和查询选项,然后调用 useQuery(generatedOptions())。键和类型来自同一来源,因此 Schema 变更会以编译错误的形式显现。模式 1。
  • 没有 Schema,或 Schema 不受你控制 — 手动编写查询函数,在解析边界验证响应,并有意设计查询键,因为没有任何内容会自动生成它们。从模式 2 开始的所有内容均适用,无需调整。

<critical_requirements>

编写 React Query 代码前

从环境变量读取 API 基础 URL。 同一构建即可在所有环境中运行。

Schema 变更时重新生成客户端,并提交生成的输出。 重新生成的类型会让不兼容的 API 变更在代码审查时成为编译错误,而不是在生产环境中造成运行时错误。

</critical_requirements>


自动检测: useQuery、useMutation、useInfiniteQuery、useSuspenseQuery、QueryClient、QueryClientProvider、QueryCache、MutationCache、queryKey、queryOptions、staleTime、gcTime、invalidateQueries、placeholderData、initialPageParam、openapi-ts

适用范围:

  • 缓存、失效处理和重新获取服务端数据
  • QueryClient 默认值、重试策略和全局错误处理
  • 从 API Schema 生成类型化查询选项
  • 依赖型、条件型和防抖查询

其他部分处理:

  • 从未来自服务端的纯客户端状态——此技能会缓存响应,不会处理用户输入的状态
  • 编写 API Schema;此技能使用已有的 Schema
  • 通过图查询语言访问的 API;其客户端缓存的是规范化实体,而不是按键缓存整个响应
  • 长期运行的套接字流——此缓存采用请求/响应模式

核心模式

模式 1:生成查询选项

将生成器指向 Schema,让它同时生成类型、服务函数和查询选项。查询键也会一并生成,因此不同调用点不会对查询键产生分歧。

// openapi-ts.config.ts
export default defineConfig({
  input: "./openapi.yaml",
  output: "src/api-client",
  plugins: ["@hey-api/typescript", "@hey-api/sdk", "@tanstack/react-query"],
});

从 @hey-api/openapi-ts v0.73 打包了一个 fetch 客户端——只有在需要自定义客户端选项时,才显式指定客户端插件。

完整代码:examples/core.md


模式 2:客户端和缓存配置

在一个 Provider 中一次性配置基础 URL 和 QueryClient 默认值。在 useState 中创建客户端,这样重新渲染就不会替换树下的缓存。

const FIVE_MINUTES_MS = 5 * 60 * 1000;

const [queryClient] = useState(
  () =>
    new QueryClient({
      defaultOptions: {
        queries: { staleTime: FIVE_MINUTES_MS, refetchOnWindowFocus: false },
      },
    }),
);

client.setConfig({ baseUrl: process.env.API_BASE_URL ?? "" });

无论如何获取数据,QueryClient 部分都适用。client 是生成的客户端,它的 setConfig() 会合并到现有配置中,而不是替换配置,因此可以在不同调用点分别设置身份验证和自定义 fetch;手写的查询函数则从原有位置读取基础 URL。

完整代码:examples/core.md — Provider 设置、静态和动态身份验证,以及一个超时后中止请求的 fetch 包装器


模式 3:使用和覆盖查询选项

直接调用生成的选项;当某个调用点需要不同的策略时,对选项进行展开。

const { data, isPending, error } = useQuery(getFeaturesOptions());

const TEN_MINUTES_MS = 10 * 60 * 1000;
const { data: slow } = useQuery({
  ...getFeaturesOptions(),
  staleTime: TEN_MINUTES_MS,
  enabled: someCondition,
});

不使用生成器时,queryOptions 辅助函数可以手动定义同样的内容,并提供类型支持:

import { queryOptions } from "@tanstack/react-query";

const featuresOptions = () =>
  queryOptions({ queryKey: ["features"], queryFn: getFeatures });

无论哪种方式,键和函数都只在一个地方声明,这样才能避免两个调用点为一个端点打开两个缓存条目,也能确保 invalidateQueries 不会只触及其中一个。展开选项会保留键,因此覆盖选项会共用同一个条目,而不是新增一个条目。

完整代码:examples/core.md


模式 4:错误处理

组件级 error 用于处理用户正在查看的查询;QueryCache 和 MutationCache 则可在一个地方处理其他所有错误。

new QueryClient({
  queryCache: new QueryCache({
    onError: (error, query) => {
      // A query that already held data failed a background refetch — the component shows stale
      // data and no error, so the notification is the only signal.
      if (query.state.data !== undefined) notify(error.message);
    },
  }),
  mutationCache: new MutationCache({
    onError: () => notify("Operation failed."),
  }),
});

完整代码:examples/error-handling.md


模式 5:条件查询和防抖查询

以防抖后的值作为查询键,并通过 enabled 控制查询,避免空搜索词发送到网络。

const DEBOUNCE_DELAY_MS = 500;

const debouncedTerm = useDebounce(searchTerm, DEBOUNCE_DELAY_MS);
const { data } = useQuery({
  queryKey: ["search", debouncedTerm],
  queryFn: () => searchApi(debouncedTerm),
  enabled: debouncedTerm.length > 0,
});

如果改用原始搜索词作为键,每次按键都会缓存一个条目。


<red_flags>

注意事项

会在运行时出错:

  • 在 useQuery 上使用 onError / onSuccess / onSettled —— 这些选项已在 v5 中移除,因此副作用不会运行,且不会发出提示。请使用组件的 error 或 QueryCache.onError。
  • 在查询函数内部调用 client.setConfig() —— 这会修改所有正在进行的请求共用的配置,因此并发查询会争抢基础 URL。
  • 使用 AbortController 设置超时,却未在成功路径中调用 clearTimeout —— 响应返回后,计时器仍会使闭包保持存活。
  • 渲染的查询既没有 error 分支,上层也没有错误边界 —— 请求被拒绝时会导致整个子树崩溃。

容易引发意外的行为:

  • setConfig() 是合并而非替换,因此部分调用会静默保留先前的身份验证配置。
  • v5 中服务端重试的默认次数为 0,而 v4 会重试三次。
  • fetch 超时与 staleTime 和 gcTime 无关 —— 前者限制单个请求的时长,后两者限制缓存条目的生命周期。
  • 对本地模拟接口保留 retry,会让一个仅仅是缺失的模拟接口导致缓慢失败。
  • 为已有 Schema 类型定义的响应手写接口,会悄然产生类型偏差:后端新增的字段既不在类型中,也不会出现在任何需要它的渲染结果中。
  • 在生成的选项旁边手写 useQuery 包装器,会让同一端点拥有两个查询键和两个缓存条目,因此失效其中一个并不会使另一个变为最新。

</red_flags>

评论

支持 Markdown