ARTICLE DETAIL

资讯详情

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

TanStack Router 的 Outlet 组件:嵌套路由如何渲染子路由

TanStack Router 的 Outlet 组件:嵌套路由如何渲染子路由 TanStack Router 的 Outlet 组件嵌套路由如何渲染子路由【免费下载链接】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 Router一个 client-first、支持服务端能力的完全类型安全的路由库与全栈框架中Outlet是嵌套路由渲染机制的核心它是一个不接收任何 props的组件用于在父路由的组件树中渲染下一个匹配的子路由。读懂Outlet你就理解了本库嵌套路由nested routing的渲染契约——子路由从哪里出现、什么时候渲染、渲染失败时如何回退到errorComponent/notFoundComponent/pendingComponent。Outlet 的基本契约根据官方 API 文档 outletComponent.mdOutlet的行为约定非常简洁propsOutlet /不接受任何 props返回值若存在匹配的子路由渲染该子路由 match 的component/errorComponent/pendingComponent/notFoundComponent即按子路由的加载状态渲染对应的 UI若没有匹配的子路由渲染null。配套的指南文档 outlets.md 进一步说明了它的典型用法Outlet /可以放在某个路由组件树的任意位置如果某条路由没有定义component框架会自动为其渲染一个Outlet /。一个经典例子是给根路由配置组件——先渲染标题再用Outlet /占位给顶层路由// React 示例 import { createRootRoute, Outlet } from tanstack/react-router export const Route createRootRoute({ component: RootComponent, }) function RootComponent() { return ( div h1My App/h1 Outlet / {/* This is where child routes will render */} /div ) }Solid 侧的用法完全一致只是从tanstack/solid-router导入createRootRoute和Outlet。源码解析Outlet 如何找到下一个子路由从源码结构看React 实现的Outlet是一个React.memo包裹的组件位于 Match.tsx。它的核心逻辑可以拆成四步开发期校验非生产环境下Outlet会读取nonRouteComponentContext如果发现自己被渲染在一个非路由组件即路由的errorComponent、notFoundComponent、pendingComponent等非 route component内部会打印警告Warning: An Outlet / was rendered inside a xxx. Outlet / should only be rendered inside a route component.也就是说Outlet /应当只出现在路由的component中——错误边界、404 边界组件里放Outlet /是反模式。定位父路由通过useRouter()拿到路由实例再从matchContext中取出当前路由的routeId该 context 由上层Match组件提供。查找子路由服务端渲染路径直接读router.stores.matches用findIndex定位父 match取其下一项的routeId作为childRouteId客户端路径通过useSelector订阅父 match 的 store选中[!!match._notFound, match.error]两个字段配合自定义比较器outletMatchSelectionEqual并从router.stores.ids中取ids.indexOf(routeId) 1对应的 id 作为childRouteId。这正是渲染下一个匹配的子路由的实现来源match 列表是有序的祖先链父 match 后面的那一项就是子 match。分支渲染父 match 处于_notFound状态时渲染renderRouteNotFound(router, route, parentNotFoundError)即 404 边界没有childRouteId时返回null与文档承诺一致否则渲染Match routeId{childRouteId} /——而根路由特例当routeId rootRouteId时Match /会被包进React.Suspense fallback{renderPending(router)}为整个应用顶层提供 loading 兜底。子路由自身处于 pending / error / notFound 状态时则由 MatchInner 处理pending状态下会throw router._tx[5]一个挂起的 promise交由最近的 Suspense 边界捕获或返回renderPendingnotFound返回renderRouteNotFounderror状态在服务端渲染errorComponent在客户端则throw match.error让错误边界接管。这就是 API 文档中返回子路由 match 的component/errorComponent/pendingComponent/notFoundComponent这一条的完整含义。未定义 component 时自动降级为 OutletAPI 文档提到不匹配则返回 null但还有一个默认行为值得注意如果路由的component未定义MatchInner会自动渲染Outlet /// packages/react-router/src/Match.tsx L210-L213 const out React.useMemo(() { const Comp route.options.component ?? router.options.defaultComponent return Comp ? Comp key{key} / : Outlet / }, [key, route.options.component, router.options.defaultComponent])这段代码同时说明了Outlet是链式的父路由没写组件 → 自动Outlet /→ 子 match 没写组件 → 再自动Outlet /逐层向下直到遇到真正定义了component的路由。这与核心库 route.ts 中component选项的注释If no component is provided, defaults toOutlet /相互印证。跨框架实现React、Solid、Vue 的 Outlet本仓库为三大框架各自提供了Outlet实现行为契约一致Solidsolid-router/src/Match.tsx 中Outlet通过nearestMatchContext取最近父级 match 与routeId同样在开发期警告渲染在非路由组件内的误用它用Solid.Show when{childRouteId()} keyed ...渲染子 matchkeyed保证子路由切换时正确卸载/重建fallback 分支则处理parentMatch()._notFound时的 404 渲染Vuevue-router/src/Match.tsx 中Outlet是Vue.defineComponent定义的具名组件name: Outlet同样保留不要渲染在非路由组件内的开发期警告。三者共享来自router-core的 match 存储与 id 序列因此取ids中父路由的下一项作为子路由这一核心逻辑在各框架间保持一致。实战要点小结Outlet /只接受零 props位置由你决定但语义是在此处渲染下一条匹配的子孙路由没有匹配时渲染null只在路由的component里使用Outlet /不要放进errorComponent/notFoundComponent/pendingComponent开发环境会收到控制台警告路由不定义component时无需手写Outlet /框架会自动补上这让纯布局透传路由只需声明路径即可子路由的 pending / error / notFound 状态由 match 状态机驱动分别落到pendingComponent、errorComponent、notFoundComponent或路由默认值根路由的Outlet /额外包一层React.SuspenseReact 侧提供顶层 pending 兜底更完整的嵌套路由使用方式可参考指南 outlets.md涉及 404 与错误渲染的语义可延伸阅读 not-found-errors.md。【免费下载链接】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),仅供参考
返回列表