一句话定义
React 是「库」,元框架(Next.js / Remix / Expo Router…)补齐路由、构建、渲染策略(SSR/SSG/RSC)、数据约定与部署——选择元框架就是选择一套工程化的 React 默认值。
为什么重要
2026 年的新项目几乎不会「裸用 React」:路由、代码分割、SEO、缓存、API 层这些必答题,元框架提供了被验证过的默认解。理解 Next.js App Router 的模型,等于理解 RSC 时代的工程全貌;同时它让你能判断「我的项目到底需要多少框架」。
前置知识
核心概念
- App Router(app/ 目录):文件夹即路由段;
page.jsx页面、layout.jsx共享布局、loading.jsx自动 Suspense、error.jsx自动 Error Boundary。 - 渲染策略光谱:静态(默认缓存)→ 动态(每请求渲染)→ 流式(Suspense 分块)——由代码里的动态 API(
cookies()、searchParams…)与revalidate决定。 - 数据层:Server Component 直接 async 取数;Server Actions 负责变更(kp-025)。
- 客户端设施:
<Link>预取、useRouter、useSearchParams、路由组(group)、并行路由与拦截路由(模态框场景)。 - 竞品定位:Remix/React Router 7 强调 Web 标准与嵌套路由;Astro 主打内容站零 JS;Expo Router 把同一套约定带进 React Native。
原理 / 机制
App Router 目录与内置容器:
textapp/
├── layout.jsx # 根布局(html/body 只在这里写一次)
├── page.jsx # 路由 "/"
├── blog/
│ ├── layout.jsx # /blog 下所有页面共享侧边栏(导航时不重渲染)
│ ├── page.jsx # /blog
│ └── [slug]/
│ ├── page.jsx # /blog/xxx —— params 动态段
│ ├── loading.jsx # 自动包一层 <Suspense fallback>
│ └── error.jsx # 自动包一层 Error Boundary(客户端组件)
└── actions.js # 'use server' 函数,供表单 action 使用
同样的「列表页 + 详情页」,App Router 的完整写法:
jsx// app/blog/page.jsx —— Server Component,构建期或请求期取数
export default async function BlogIndex() {
const posts = await db.post.list();
return (
<ul>
{posts.map(p => (
<li key={p.id}><Link href={`/blog/${p.slug}`}>{p.title}</Link></li>
))}
</ul>
);
}
// app/blog/[slug]/page.jsx
export async function generateMetadata({ params }) { // SEO 元数据即函数
const post = await db.post.find(params.slug);
return { title: post.title, description: post.excerpt };
}
export default async function Post({ params }) {
const post = await db.post.find(params.slug);
return <article>{/* … */}</article>;
}
对比 SPA:路由、数据获取(组件里 await)、SEO(generateMetadata)、加载态(loading.jsx)四处胶水代码全部被约定吸收——这就是「元框架的价值」的可视化。
渲染策略的选择心法:
text内容为主、更新少(文档/博客) → 默认静态 + 按需 revalidate
个性化仪表盘(每请求不同) → 动态渲染 + 流式 Suspense
重交互工具(编辑器/Figma 类) → 大量 'use client',甚至该考虑纯 SPA
直观类比
React 像一台发动机,元框架是整车厂:发动机好不代表能上路——底盘(路由)、变速箱(构建)、安全带(SEO/错误处理)、4S 店(部署)缺一不可。App Router 的文件约定像酒店房间服务菜单:loading.jsx 点了就有,error.jsx 点了就有——你在对的文件名里写下组件,框架负责在正确的时机端上来。
实例 / 案例
学习路径终局项目的结构(书签管理器 → Next.js 版):
textapp/
├── layout.jsx # 根布局 + 主题 Provider('use client' 壳)
├── (site)/
│ ├── page.jsx # 书签列表:Server 直查库
│ ├── loading.jsx # 骨架屏
│ └── actions.js # 添加/删除书签的 Server Actions
└── api/… # 需要原始 JSON 的极少数端点
技术决策记录(真实项目该写的 ADR):
- RSC 默认 + 叶子交互 'use client'(SearchBox、标签筛选)
- 表单用 Actions + useOptimistic(kp-025)
- 客户端全局状态只剩「视图偏好」→ Zustand(kp-021)
- 部署 Vercel / 自托管 Node
常见误区
- 'use client' 加在 layout 或整个分支上:RSC 边界应下沉(kp-024 误区在框架层的放大);客户端壳越厚,RSC 收益越薄。
- 以为「静态优先」= 内容不会更新:revalidate/按需失效机制专门解决这个问题;搞不清缓存层级是 App Router 最陡的学习曲线。
- 在 Server Component 里用 hooks/事件:类型直接报错(好事);把交互需求交给 Client 子组件或 Actions。
- 把 API Routes 当万能层:多数取数不需要经 API——组件里 await 即可;API Route 留给外部消费者与 Webhook。
- 「Next.js = SEO 才需要」:路由约定、代码分割、缓存、Actions 全都是与 SEO 无关的工程收益。
自测题
- 画出 App Router 中 page/layout/loading/error 四件套的职责与自动包装关系。
- 「这个页面该静态还是动态」的判断依据是什么?列三个信号。
- 为什么 Server Component 里不需要 API Route?什么时候仍需要?
- 给「营销官网 + 用户后台」的混合产品设计路由结构,标出每段的渲染策略。
- 'use client' 放在页面顶部 vs 放在叶子组件,对 bundle 的影响差多少量级?为什么?
与其他知识点的关系
- 向前:RSC(kp-024)与 Actions(kp-025)的工程化容器。
- 向后:kp-027 的测试在该结构下分层(Server 逻辑用 Node 测试、Client 组件用 Testing Library);kp-028 的审查清单含「客户端边界是否下沉」;kp-021 的状态库在 RSC 时代被压缩到「纯客户端状态」这一小块。
延伸阅读
- Next.js Docs(App Router):<https://nextjs.org/docs>
- Learn Next.js 官方课程:<https://nextjs.org/learn>
- Remix 思想文档(对比视角):<https://remix.run/docs/en/main/discussion/progressive-enhancement>