恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Storybook for TanStack React 中注入 TanStack Query 数据:借助 beforeEach 与 setQueryData 为每个故事预置缓存状态

  • 首页
  • 资讯中心
  • /
  • Storybook for TanStack React 中注入 TanStack Query 数据:借助 beforeEach 与 setQueryData 为每个故事预置缓存状态

相关资讯

楼宇微网虚拟储能系统优化与PSO算法实现 2026/9/10 14:51:00
CANN/GE 算子编译标识设置接口(已废弃) 2026/9/10 14:51:00
Repomix 内存泄漏检测与基准测试实战:scripts/memory 工具链完全指南 2026/9/10 14:51:00

最新资讯

农村土地二轮延包政策实施中的数据分析局限与实践重点
生成式AI时代:搜索引擎优化(GEO)的核心技术与实战策略
Mongoose 5.x 升级 6.x 迁移指南:破坏性变更全解析与源码级应对方案
储能电站多时间尺度调度与Matlab实现
读懂CPU错误码06H:从机器检查异常到硬件根因定位
Vivo手机数据备份与恢复全攻略

今日推荐

AI搜索重构内容生态:企业从“流量争夺”转向“答案共建”
AI搜索的信任缺口:企业内容如何在答案时代自证可信
Spring Boot+Vue+Node.js售后服务系统开发实战

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Storybook for TanStack React 中注入 TanStack Query 数据:借助 beforeEach 与 setQueryData 为每个故事预置缓存状态

发布时间:2026/9/10 14:51:00
Storybook for TanStack React 中注入 TanStack Query 数据:借助 beforeEach 与 setQueryData 为每个故事预置缓存状态 Storybook for TanStack React 中注入 TanStack Query 数据借助 beforeEach 与 setQueryData 为每个故事预置缓存状态【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook导读本文基于 Storybook 仓库中的 TanStack React 框架文档与源码系统讲解如何在 Storybook 中为基于 TanStack Router / TanStack Start 的 React 应用配置 TanStack Query并在每个故事渲染前通过beforeEach钩子调用QueryClient.setQueryData预置查询缓存。读完本文你将掌握parameters.tanstack.router.context与QueryClientProvider的协作模式、CSF 3 与 CSF Next 两种写法以及底层路由上下文注入的实现原理能够独立复现登录态 Navbar加载中/成功/失败等依赖服务端数据的组件故事。一、为什么需要在 Story 中预置 Query 数据在真实的 TanStack Router 应用中组件往往通过useQuery从服务端拉取数据。而在 Storybook 中我们并不希望每个故事都真的发起网络请求——更常见的诉求是把某个查询键query key对应的缓存数据直接写入QueryClient让组件在渲染时立即读到确定的初始状态从而稳定展示已登录用户空列表错误提示等场景。storybook/tanstack-react框架本身只处理路由与 server function 的 mock详见 tanstack-react.mdx 中的 TanStack Query 一节TanStack Query 并不会被自动接入需要开发者手动把QueryClient接入 Storybook 的渲染管线。接入的关键是两个协同点通过parameters.tanstack.router.context把QueryClient注入到故事路由的 router context 中使路由loader、beforeLoad以及故事的beforeEach都能读取到它通过QueryClientProvider装饰器把同一个QueryClient提供给组件树使useQuery等 hooks 正常工作。核心文档片段见 docs/_snippets/tanstack-react-query-in-story.md项目级初始化见 docs/_snippets/tanstack-react-query-setup.md。二、项目级设置在 Preview 文件中创建共享 QueryClient官方推荐在.storybook/preview.tsx中创建一个唯一的QueryClient单例并在每个故事开始前清空缓存让每个故事从零开始。CSF 3 写法如下完整代码见 tanstack-react-query-setup.mdimport { type QueryClient, QueryClientProvider } from tanstack/react-query; import type { Preview } from storybook/tanstack-react; // Create a new QueryClient const queryClient new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity, }, }, }); const preview: Preview { beforeEach: () { // Clear the cache between stories so each story starts fresh queryClient.clear(); }, parameters: { tanstack: { router: { // Make queryClient available in stories beforeEach via ctx.context.queryClient context: { queryClient }, }, }, }, decorators: [ (Story) ( // Provide the QueryClient to all stories QueryClientProvider client{queryClient} Story / /QueryClientProvider ), ], }; export default preview;这段配置包含三个相互配合的要点defaultOptions.queriesretry: false避免失败查询在故事渲染时反复重试staleTime: Infinity让预置的缓存数据不会因为过期而触发重新拉取保证setQueryData写入的数据稳定生效。beforeEach: () queryClient.clear()在每条故事渲染前清空缓存确保故事之间互不污染clear()是同步方法会同时移除缓存条目并重置观察者状态。parameters.tanstack.router.context与decorators前者把queryClient放进路由上下文供beforeEach、路由loader读取后者用QueryClientProvider把它提供给 React 组件树。二者指向同一个实例是预置的数据能被组件读到的前提。如果你使用的是 CSF Next实验性可改用definePreview的等价写法import { definePreview } from storybook/tanstack-react; import { type QueryClient, QueryClientProvider } from tanstack/react-query; // Create a new QueryClient const queryClient new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity, }, }, }); export default definePreview({ beforeEach: () { // Clear the cache between stories so each story starts fresh queryClient.clear(); }, parameters: { tanstack: { router: { // Make queryClient available in stories beforeEach via ctx.context.queryClient context: { queryClient }, }, }, }, decorators: [ (Story) ( // Provide the QueryClient to all stories QueryClientProvider client{queryClient} Story / /QueryClientProvider ), ], });这种单例 每故事清空的模式保证了无论 Storybook 以何种方式渲染故事——侧边栏画布、Docs 页面、portable stories 或测试运行——router context 与 React Provider 始终指向同一个QueryClient行为完全一致。三、按故事预置查询数据beforeEach setQueryData项目级配置就绪后在具体的故事中即可通过beforeEach钩子在组件渲染之前把缓存数据写入QueryClient。核心文档 tanstack-react-query-in-story.md 给出了一个典型场景Navbar 组件依赖[currentUser]这条查询未登录与已登录两种状态分别对应不同的故事。CSF 3 写法import type { Meta, StoryObj } from storybook/tanstack-react; import type { QueryClient } from tanstack/react-query; import { Navbar } from ./Navbar; const meta { component: Navbar, } satisfies Metatypeof Navbar; export default meta; type Story StoryObjtypeof meta; export const Default: Story {}; export const LoggedIn: Story { beforeEach: async ({ parameters }) { const qc: QueryClient parameters.tanstack?.router?.context?.queryClient; qc?.setQueryData([currentUser], { id: user-1, name: Ada Lovelace, }); }, };CSF Next 写法import type { QueryClient } from tanstack/react-query; import preview from ../.storybook/preview; import { Navbar } from ./Navbar; const meta preview.meta({ component: Navbar, }); export const Default meta.story(); export const LoggedIn meta.story({ beforeEach: async ({ parameters }) { const qc: QueryClient parameters.tanstack?.router?.context?.queryClient; qc?.setQueryData([currentUser], { id: user-1, name: Ada Lovelace, }); }, });关键要点解析beforeEach的执行时机它运行于组件渲染之前Storybook 的beforeEach机制详见 interaction-testing.mdx因此此时写入的setQueryData数据会在组件首次渲染时即可用。beforeEach可以返回一个清理函数该函数会在故事被重新挂载或导航离开之后运行用于回收每个故事创建的资源。parameters.tanstack?.router?.context?.queryClient这是从路由上下文取回共享QueryClient的标准入口与 Preview 文件中context: { queryClient }的配置一一对应。用可选链?.访问保证在上下文缺失时安全降级。setQueryData([currentUser], ...)第一个参数是查询键query key必须与组件中useQuery({ queryKey: [currentUser], ... })的键保持一致第二个参数是缓存数据。写入后组件通过useQuery读取到的就是这份数据而不会发出网络请求。Default: Story {}未登录故事不注入任何数据组件会走空态/加载态渲染路径LoggedIn注入数据后走已登录路径。同一个组件文件内即可完整覆盖多种状态。四、底层原理路由上下文是如何把 QueryClient 送到 beforeEach 的理解了用法之后再来看storybook/tanstack-react源码中这一链路的具体实现可以更好地判断何时该用context、何时该用useRouterContext。4.1 routerBeforeEach渲染前创建并加载故事路由框架在code/frameworks/tanstack-react/src/routing/before-each.ts中实现了routerBeforeEach钩子L11-L49。每个故事在渲染前都会执行以下流程从context.parameters.tanstack?.router读取路由参数若context是工厂函数typeof parameterContext function则在 React 渲染之外调用它得到最终的 router context 对象——这正是context: ({ storyContext }) ({ queryClient })这种工厂写法能工作的原因调用createStoryRouter创建内存路由器并执行router.load()将路由器缓存到storyRoutersMap 中并挂到context.tanstackRouter上供装饰器使用。由于故事级beforeEach与routerBeforeEach同属渲染前的执行阶段此时从parameters.tanstack.router.context取到的queryClient一定已经可用。4.2 装饰器用 RouterProvider 包住故事在code/frameworks/tanstack-react/src/routing/decorator.tsx中tanstackRouteDecoratorL50-L52把故事包进TanStackRouterStoryL54-L78从context.tanstackRouter取出路由器通过RouterProvider渲染并注入由parameters.tanstack.router.useRouterContext若提供计算出的上下文。createStoryRouterL80-L125则负责把params插值进路径、拼接query搜索参数、创建createMemoryHistory内存历史最终createRouter({ routeTree, history, context: routerContext, ... })。也就是说context最终会作为 TanStack Router 的 router context 存在而组件与beforeEach都通过这条路径访问到同一个QueryClient。4.3 context 工厂 vs useRouterContext两条注入通道的分工框架在code/frameworks/tanstack-react/src/routing/types.ts中定义了两种上下文注入方式L186-L192参数类型执行时机适用场景contextRecordstring, unknown \| (({ storyContext }) Recordstring, unknown)初始路由加载之前、React 渲染之外路由loader/beforeLoad需要读取的值如queryClient或beforeEach需要访问的值useRouterContext({ storyContext }) RouterContextReact hook渲染期间初始加载完成后只能从 React Provider 中读取的值例如const queryClient useQueryClient()两条通道的差异很关键因为useRouterContext是 hook它在 router 的 initial load 完成之后才执行其返回值不会出现在初始loader/beforeLoad中而context工厂在初始加载之前运行所以凡是路由 loader 要读的值必须走context通道。框架自带的示例 RouterContextInjection.stories.tsx 展示了如何用useRouterContext从装饰器提供的 React Context 中取值并注入路由。对我们的场景而言由于beforeEach需要在渲染前读取queryClient因此项目级配置中选择context: { queryClient }静态对象即可是最稳妥的方案。五、隔离策略何时为每个故事单独创建 QueryClient默认的单例 queryClient.clear()模式适合绝大多数场景。但官方文档tanstack-react.mdx 的 TanStack Query 一节也指出了需要更强隔离的例外当你在同一个 Docs 页面上渲染多个使用相同查询键的故事且希望它们的缓存响应彼此独立时可以为每个故事创建独立的QueryClient。采用该策略必须同时满足两个条件否则会出现难以排查的数据对不上问题router context 与QueryClientProvider必须指向同一个 per-story 客户端。如果二者拿到的是不同实例路由loader和组件可能读到两套缓存beforeEach中setQueryData写入的数据也可能对组件完全无效。需要显式清理每个客户端拥有的计时器、订阅与缓存数据。单例模式下由 Preview 的beforeEach统一clear()改为 per-story 后这部分职责要转移到故事自身可在故事级beforeEach的返回清理函数中处理。六、实践要点与常见问题6.1 查询键必须与组件一致setQueryData的查询键要与组件内useQuery的查询键完全一致序列化结果相同。键不一致时写入的缓存不会被组件读取到故事会退化为真实请求或空态。若组件使用函数式查询键依赖参数写入时也要按相同规则构造键。6.2 需要同时控制路由 loader 与 Query 缓存如果数据由路由loader提供而非组件内useQuery那么beforeEach中的setQueryData可能不是正确的位置——此时应在parameters.tanstack.router.routeOverrides中按路由 ID 覆写loader详见 tanstack-react.mdx 的 Overriding route options per story 一节以及 types.ts 中RouteOverrideOptions的定义。setQueryData只解决TanStack Query 缓存这一层路由数据与查询数据是两条不同的数据通路。6.3 组件没有读取到预置数据怎么办按以下顺序排查确认 Preview 文件中的context: { queryClient }与QueryClientProvider client{queryClient}指向同一实例确认故事beforeEach中的键parameters.tanstack?.router?.context?.queryClient拼写无误确认setQueryData的查询键与useQuery的键一致确认staleTime未被设置为会触发重新拉取的配置如staleTime: 0配合refetchOnMount必要时参考 Preview 示例使用staleTime: Infinity。6.4 数据写入时机与异步场景beforeEach是异步函数setQueryData是同步 API因此可以直接在beforeEach中连续写入多条查询无需额外await。若组件依赖异步拉取后的状态则更适合在组件测试或play函数中配合waitFor断言而不是在beforeEach中模拟。七、小结在 Storybook for TanStack React 中接入 TanStack Query 的核心模式可以概括为三步在.storybook/preview.tsx创建QueryClient单例通过beforeEach每故事clear()通过parameters.tanstack.router.context与QueryClientProvider装饰器把同一实例注入路由上下文与组件树在具体故事的beforeEach中调用qc.setQueryData([key], data)预置缓存。这一模式源自官方文档 docs/get-started/frameworks/tanstack-react.mdx 的 TanStack Query 章节其配套示例可在 tanstack-react-query-setup.md 与 tanstack-react-query-in-story.md 中查看底层实现可继续阅读 before-each.ts、decorator.tsx 与 types.ts 加深理解。掌握这套模式后你可以为任意依赖查询缓存的组件编写覆盖登录态、空态、错误态等完整状态矩阵的故事且无需修改任何应用代码。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号