01 · NOTES / WebGIS 开发
第 21 节 · 路由与布局(动态段/加载/错误)
2026 年 9 月 1 日
第 21 节 · 路由与布局(动态段/加载/错误)
📌 版本信息:Next.js 15.x App Router(2026-08-29 核对) 📚 来源:Next.js · Dynamic Routes | Loading/Error UI ▶️ 配套练习:
examples/21-博客式结构/(文章详情动态段 + loading/error/not-found 全套——C-03c 的骨架预演)
一、这一节的目标
- 掌握动态段
[slug]与 params 的接收 - 掌握三个约定文件:loading.js / error.js / not-found.js
- 会用嵌套布局组织分区(侧栏式博客结构)
- 完成"博客式结构"——文章站的完整路由形态
二、动态段:[slug]
// app/blog/[slug]/page.js —— 匹配 /blog/任意一段
export default function BlogPost({ params }) {
const slug = params.slug; // /blog/hello-world → 'hello-world'(字符串)
const post = getPost(slug);
if (!post) notFound(); // 触发 not-found.js(找不到内容的标准姿势)
return <article>{post.title}</article>;
}
- 多段动态:
app/docs/[...slug]/page.js(捕获剩余所有段,全段动态) - 动态段默认使页面变为动态渲染;配合
generateStaticParams把已知参数在构建时生成静态页(SSG,第 25 节详讲)
三、三个约定文件:体验的保险丝
| 文件 | 触发时机 | 作用 |
|---|---|---|
loading.js |
该路由段的页面/数据加载期间 | 自动包住页面的骨架屏(React Suspense 的约定化) |
error.js |
该段渲染抛错时 | 错误兜底 UI(必须是客户端组件 "use client",含重试按钮) |
not-found.js |
调用 notFound() 或 404 | 未找到 UI |
// app/blog/loading.js —— 零配置骨架屏
export default function Loading() {
return <p>文章加载中…</p>;
}
// app/blog/error.js —— 必须客户端组件 + 提供重置(重试)
'use client';
export default function Error({ error, reset }) {
return (
<div>
<p>出错了:{error.message}</p>
<button onClick={reset}>重试</button> {/* reset:重新渲染该段 */}
</div>
);
}
粒度即体验:约定文件放在哪一层就管哪一层子树——只在 blog/ 下放 loading.js,首页切换就不受影响。这正是"每段独立加载 UI"的流式渲染基础(第 25 节)。
四、动手跟练:21 · 博客式结构
配套文件夹:03-react-nextjs/examples/21-博客式结构/(npm i && npm run dev)
步骤:
- 结构:
/blog(列表)→/blog/[slug](详情,含 loading/error/not-found 全套) - 完成 5 个 TODO:详情页读取 params 并匹配数据(不匹配调 notFound)、把手写
<a>全换next/link(体验零刷新)、给 loading.js 换成骨架条样式、error.js 的 reset 验证(故意把一条数据指向不存在的 slug)、给 blog 段加嵌套 layout(左侧"最新文章"侧栏) - Network 面板观察:进入详情页时的 RSC 载荷请求(Next 的服务端组件"补丁",第 23 节揭晓原理)
通关标准:
-
/blog/hello出文章、/blog/none出 404、抛错出 error UI 且能重试 - 全站导航零刷新(全 Link)
- 能说出三个约定文件各自的触发条件与放置粒度
五、自测题
- params.slug 的类型?动态段让页面变成什么渲染模式?
- notFound() 从哪 import?调用后发生什么?
- error.js 为什么必须 "use client"?reset 干什么?
- loading.js 的底层机制是什么(React 哪个特性)?
- 想让"仅文章详情页有骨架屏、列表页没有",loading.js 放哪?
参考答案
- 字符串;动态段默认使页面动态渲染(配合 generateStaticParams 可转 SSG)。
next/navigation;抛出一个特殊信号,渲染最近的 not-found.js。- 错误 UI 需要交互(重试按钮 onClick);reset 重新渲染出错的该段(清错误状态重试)。
- React 的 Suspense——约定文件自动把该段页面包进 Suspense 边界。
- 放
app/blog/[slug]/loading.js(只管动态详情段;放 blog/ 会连列表页一起包)。
六、下一步
路由体系完备 → 第 22 节:数据获取,服务端 fetch 与缓存初识。
TAGSweb