TanStack Router 包含多项优化,以确保您的组件仅在必要时重新渲染。这些优化包括:
TanStack Router 使用一种称为"结构共享"的技术来在重新渲染之间保留尽可能多的引用,这对于存储在 URL 中的状态(如搜索参数)特别有用。
例如,考虑一个具有两个搜索参数 foo 和 bar 的 details 路由,访问方式如下:
const search = Route.useSearch()
const search = Route.useSearch()
当仅通过从 /details?foo=f1&bar=b1 导航到 /details?foo=f1&bar=b2 更改 bar 时,search.foo 将保持引用稳定,只有 search.bar 会被替换。
您可以使用各种钩子(如 useRouterState、useSearch 等)访问和订阅路由器状态。如果您只希望特定组件在路由器状态的特定子集(如搜索参数的子集)更改时重新渲染,可以使用带有 select 属性的部分订阅。
// component won't re-render when `bar` changes
const foo = Route.useSearch({ select: ({ foo }) => foo })
// component won't re-render when `bar` changes
const foo = Route.useSearch({ select: ({ foo }) => foo })
select 函数可以对路由器状态执行各种计算,允许您返回不同类型的值,例如对象。例如:
const result = Route.useSearch({
select: (search) => {
return {
foo: search.foo,
hello: `hello ${search.foo}`,
}
},
})
const result = Route.useSearch({
select: (search) => {
return {
foo: search.foo,
hello: `hello ${search.foo}`,
}
},
})
Although this works, it will cause your component to re-render each time, since select is now returning a new object each time it’s called.
You can avoid this re-rendering issue by using "structural sharing" as described above. By default, structural sharing is turned off to maintain backward compatibility, but this may change in v2.
To enable structural sharing for fine grained selectors, you have two options:
const router = createRouter({
routeTree,
defaultStructuralSharing: true,
})
const router = createRouter({
routeTree,
defaultStructuralSharing: true,
})
const result = Route.useSearch({
select: (search) => {
return {
foo: search.foo,
hello: `hello ${search.foo}`,
}
},
structuralSharing: true,
})
const result = Route.useSearch({
select: (search) => {
return {
foo: search.foo,
hello: `hello ${search.foo}`,
}
},
structuralSharing: true,
})
Important
结构共享仅适用于 JSON 兼容的数据。这意味着如果启用了结构共享,您不能使用 select 返回类实例等项目。
与 TanStack Router 的类型安全设计一致,如果您尝试以下操作,TypeScript 将引发错误:
const result = Route.useSearch({
select: (search) => {
return {
date: new Date(),
}
},
structuralSharing: true,
})
const result = Route.useSearch({
select: (search) => {
return {
date: new Date(),
}
},
structuralSharing: true,
})
如果在路由器选项中默认启用了结构共享,您可以通过设置 structuralSharing: false 来防止此错误。