TanStack Router 包含多项优化,以确保您的组件仅在必要时重新渲染。这些优化包括:
TanStack Router 使用一种称为“结构共享”的技术,在重新渲染之间保留尽可能多的引用,这对于存储在 URL 中的状态(例如搜索参数)特别有用。
例如,考虑一个具有两个搜索参数 foo 和 bar 的 details 路由,访问方式如下:
const search = Route.useSearch()
const search = Route.useSearch()
当仅 bar 改变时(从 /details?foo=f1&bar=b1 导航到 /details?foo=f1&bar=b2),search.foo 将保持引用稳定,只有 search.bar 会被替换。
您可以使用 useRouterState、useSearch 等各种 Hook 访问和订阅路由器状态。如果您只想在路由器状态的特定子集(例如搜索参数的子集)发生变化时才重新渲染特定组件,则可以使用带有 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}`,
}
},
})
尽管这可行,但它会导致您的组件每次都重新渲染,因为 select 每次被调用时都会返回一个新对象。
您可以通过使用上面描述的“结构共享”来避免此重新渲染问题。默认情况下,为了保持向后兼容性,结构共享是关闭的,但这可能会在 v2 中改变。
要为细粒度选择器启用结构共享,您有两种选择:
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,
})
重要
结构共享仅适用于 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 来防止此错误。
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。