路由搭建
配置基于文件的路由,带布局、嵌套路由和类型化参数。
为什么
路由是应用骨架——每页、每布局、每导航过渡流经它。配置良好的路由给你嵌套布局(侧边栏 + 内容)、类型化路由参数(不再字符串解析)、每路由代码分割(更快初始加载)。基于文件路由(Next.js app router、TanStack Router)消除路由配置文件——文件系统即路由树,加页是建文件非编辑配置。类型化参数(useParams<{ id: string }>())编译时抓错参数名而非运行时渲染 undefined。
何时使用
应用有 ≥3 页时。约 1-2 小时。单页应用可跳过。
如何做
1. 用框架基于文件路由(Next.js app/、TanStack Router、Remix)
- app/dashboard/users/[id]/page.tsx → /dashboard/users/:id
- 布局:layout.tsx 包目录所有页
2. 用框架类型化参数类型化路由参数
- Next.js:const { id } = useParams<{ id: string }>()
- TanStack Router:生成 routeTree.gen.ts 全类型安全
3. 加根布局带共享外壳(头、尾、错误边界)
- 此布局包每路由;保持最小(无数据获取)
- 嵌套布局组合:root > dashboard > users > [id]
4. 每路由加 loading.tsx(Next.js)或 suspense fallback
- 数据获取时显示骨架非空白页
- 每路由代码分割,初始 bundle 仅含落地页
5. 每路由段加 not-found.tsx 和 error.tsx
- 404 和错误应在应用外壳渲染,非白页示例
// app/dashboard/users/[id]/page.tsx(Next.js app router)
import { useParams } from "next/navigation";
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await getUser(params.id); // 类型化参数,无解析
return <UserDetail user={user} />;
}
// app/dashboard/layout.tsx(嵌套布局)
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex">
<Sidebar />
<main className="flex-1">{children}</main>
</div>
);
}
// app/dashboard/users/[id]/loading.tsx
export default function Loading() { return <UserDetailSkeleton />; }
// app/dashboard/users/[id]/error.tsx
export default function Error({ error }: { error: Error }) {
return <ErrorBoundary error={error} />;
}常见问题
- ⚠parseInt 解析参数无验证,/users/abc 渲染 NaN 作 ID。
- ⚠根布局放数据获取,每次导航全重取。
- ⚠无加载状态,导航到数据重页显空白 2 秒。
- ⚠根单一错误边界,一路由 bug 杀全应用。
最佳实践
- ✓用类型化路由参数(Next.js:params 有类型;TanStack Router:全路径类型安全)编译时抓拼写错。
- ✓布局薄——仅共享外壳,无数据获取——不阻塞导航。
- ✓每数据获取路由加 loading.tsx,用户看骨架非空白页。
- ✓共享布局的模态和条件用并行路由(Next.js @slot)。