十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何用结构共享与 select 细粒度订阅减少 TanStack Router 组件重复渲染

如何用结构共享与 select 细粒度订阅减少 TanStack Router 组件重复渲染 如何用结构共享与 select 细粒度订阅减少 TanStack Router 组件重复渲染【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router如果你用 TanStack Routertanstack/react-router把分页、筛选条件等状态放在 URL search params 里可能会遇到这种情况某个组件只用到了search.foo但用户修改search.bar后它也跟着重新渲染。TanStack Router 提供了两个互补的手段来解决这个问题**细粒度选择器select**让组件只订阅 router state 的一个子集**结构共享structural sharing**让select返回的对象在值没变时保持引用稳定。本文按先用select缩小订阅范围再按需开启 structural sharing的顺序给出完整配置路径全部内容来自仓库内的 Render Optimizations 指南。重复渲染来自哪里先明确文档给出的两个触发点这决定了后两步优化分别针对什么订阅了不需要的状态。像useSearch、useRouterState这类 hook 返回完整的 search 对象或 router stateURL 中任意 search param 变化都会让订阅它的组件重新渲染。select每次返回新对象。当select函数返回对象时每次调用都会产生一个新的对象引用即使内部字段值完全没变组件也会重新渲染。另外要注意结构共享默认是关闭的文档说明这是为了保持向后兼容且这一点在 v2 中可能会改变见 Render Optimizations。所以在做任何订阅优化之前先确认你的项目没有开启它。第一步用select缩小订阅范围useSearch支持select选项函数接收 search 对象返回值直接作为 hook 的返回值。官方文档给出的示例是一个带foo、bar两个 search params 的details路由// component wont re-render when bar changes const foo Route.useSearch({ select: ({ foo }) foo })文档对上面这行的行为判定是当导航从/details?foof1barb1到/details?foof1barb2时组件不会因为bar的变化而重新渲染。Route.useSearch()是路由上的类型化 hook如果在别的组件里读取某条路由的 search params使用顶层useSearch并传入from选项useSearch hook APIimport { useSearch } from tanstack/react-router const selected useSearch({ from: /posts/$postId, select: (search) search.postView, })select不是useSearch独有的。useRouterState同样提供select与structuralSharing两个选项例如只订阅 locationconst selected useRouterState({ select: (state) state.location, })useRouterState hook API 中还有一条建议如果只是要拿当前 location 或 matches优先考虑useLocation、useMatches这类 hook它们比直接读useRouterState更轻量。此外仓库 API 文档中useMatches、useChildMatches、useParentMatches、useParams、useLoaderData、useLoaderDeps、useMatch等 hook 也都定义了structuralSharing选项订阅 router state 的其他位置可以按同样思路处理。到这一步能解决订阅面过大的问题。但如果你希望select返回对象而不是单个字段就会撞上第二个触发点const result Route.useSearch({ select: (search) { return { foo: search.foo, hello: hello ${search.foo}, } }, })文档明确指出这样写的话select每次调用都返回一个新对象组件会因此重新渲染。解决办法是下一步的 structural sharing。第二步开启 structural sharing 让 select 返回的对象保持引用稳定TanStack Router 对 search params 本来就内置了结构共享导航只改bar时search.foo保持引用稳定只有search.bar被替换见 Render Optimizations。对于select返回的值需要显式开启结构共享文档给了两种互斥的开启方式方式一在 router 选项中全局默认开启const router createRouter({ routeTree, defaultStructuralSharing: true, })defaultStructuralSharing是RouterOptions的一个可选项类型boolean默认值为false作用是为细粒度选择器默认启用 structural sharing见 RouterOptions API。方式二按 hook 调用点单独开启const result Route.useSearch({ select: (search) { return { foo: search.foo, hello: hello ${search.foo}, } }, structuralSharing: true, })structuralSharing选项的定义是配置select返回值是否启用 structural sharing见 useSearch hook API 的opts.structuralSharing一节。选择建议如果整个应用里大量 hook 都需要select返回对象用方式一全局开启更省事如果只是个别订阅点需要用方式二局部开启避免影响其他调用点的默认行为。如何验证优化是否生效文档给出的可观察判定如下可直接用于核对订阅收窄生效按第一步的示例导航只修改未被订阅的参数如bar时使用该select订阅的组件不应重新渲染。这是文档对select: ({ foo }) foo的直接行为描述。结构共享生效导航/details?foof1barb1→/details?foof1barb2时search.foo引用保持不变只有search.bar被替换。类型层面对开启 structural sharing 的调用做约束如果你让select返回 class 实例如new Date()并开启structuralSharing: trueTypeScript 会直接报错const result Route.useSearch({ select: (search) { return { date: new Date(), } }, structuralSharing: true, })也就是说非 JSON 兼容的返回值在编译期就能被拦截这本身也是一次免费的检查。限制与回退structural sharing 只支持 JSON 兼容的数据。开启后不能用select返回 class 实例之类的值上面的new Date()例子在类型上会报错这是预期行为而不是 bug。如果按方式一在 router 选项里全局开启了defaultStructuralSharing个别必须返回非 JSON 数据或不想做结构共享的调用点可以单独设置structuralSharing: false来规避。默认关闭且 v2 可能改变文档明确说明结构共享默认关闭是为了向后兼容this may change in v2。升级版本时建议重新确认defaultStructuralSharing的默认值。完成上述两步后订阅面过大和select返回新对象两个触发点都已被覆盖前者用select解决后者用defaultStructuralSharing或逐点的structuralSharing解决。更多 hook 的select/structuralSharing细节可查阅 Render Optimizations 指南 与docs/router/api/router/下各 hook 的 API 文档。【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表