页面与布局
特殊文件 layout.js、page.js 和 template.js 允许您为路由创建用户界面。本文将指导您如何使用这些特殊文件及其适用场景。
页面
页面是路由的专属用户界面。您可以通过从 page.js
文件默认导出一个组件来定义页面。
例如,要在 app
目录中创建首页,添加 page.js
文件:

要创建更多页面,只需新建文件夹并在其中添加 page.js
文件。例如,为 /dashboard
路由创建页面时,新建名为 dashboard
的文件夹并添加 page.js
文件:
须知:
- 页面可以使用
.js
、.jsx
或.tsx
文件扩展名- 页面始终是路由子树的叶节点
- 必须存在
page.js
文件才能使路由段可公开访问- 页面默认为服务端组件 (Server Components),但可设置为客户端组件 (Client Component)
- 页面可以获取数据,详见数据获取章节
布局
布局是多个路由间共享的用户界面。在导航时,布局会保留状态、保持交互性且不会重新渲染。布局还可以进行嵌套。
您可以通过从 layout.js
文件默认导出一个 React 组件来定义布局。该组件应接收一个 children
属性,该属性会在渲染时填充为子布局(如果存在)或页面。
例如,以下布局将与 /dashboard
和 /dashboard/settings
页面共享:

根布局 (必需)
根布局定义在 app
目录的顶层,适用于所有路由。该布局是必需的,必须包含 html
和 body
标签,以便修改从服务器返回的初始 HTML。
嵌套布局
默认情况下,文件夹层次结构中的布局会嵌套,即通过 children
属性包裹子布局。您可以在特定路由段(文件夹)中添加 layout.js
来实现布局嵌套。
例如,要为 /dashboard
路由创建布局,在 dashboard
文件夹中添加新的 layout.js
文件:

如果结合上述两个布局,根布局 (app/layout.js
) 将包裹仪表盘布局 (app/dashboard/layout.js
),后者又会包裹 app/dashboard/*
中的路由段。
这两个布局的嵌套关系如下:

须知:
- 布局可以使用
.js
、.jsx
或.tsx
文件扩展名- 只有根布局可以包含
<html>
和<body>
标签- 当同一文件夹中存在
layout.js
和page.js
时,布局将包裹页面- 布局默认为服务端组件 (Server Components),但可设置为客户端组件 (Client Component)
- 布局可以获取数据,详见数据获取章节
- 无法在父布局与其子级之间传递数据。但您可以在路由中多次获取相同数据,React 会自动去重请求且不影响性能
- 布局无法访问其下方的路由段。要访问所有路由段,可在客户端组件中使用
useSelectedLayoutSegment
或useSelectedLayoutSegments
- 可以使用路由组 (Route Groups) 选择性地让特定路由段加入或退出共享布局
- 可以使用路由组 (Route Groups) 创建多个根布局,参见示例
- 从
pages
目录迁移: 根布局替代了_app.js
和_document.js
文件。查看迁移指南
模板
模板与布局类似,都会包裹每个子布局或页面。但与跨路由持久化并保持状态的布局不同,模板在导航时会为每个子级创建新实例。这意味着当用户在共享模板的路由间导航时,会挂载组件的新实例、重新创建 DOM 元素、不保留状态且会重新同步副作用。
在某些需要这些特定行为的场景下,模板比布局更合适。例如:
- 依赖
useEffect
的功能(如记录页面访问)和useState
(如每页反馈表单) - 更改框架默认行为。例如,布局中的 Suspense 边界仅在首次加载布局时显示回退内容,而模板会在每次导航时显示回退内容
可以通过从 template.js
文件默认导出一个 React 组件来定义模板。该组件应接收 children
属性。

在嵌套方面,template.js
会在布局与其子级之间渲染。以下是简化后的输出:
元数据
在 app
目录中,您可以使用元数据 API (Metadata APIs) 修改 <head>
HTML 元素,如 title
和 meta
。
通过在 layout.js
或 page.js
文件中导出 metadata
对象 或 generateMetadata
函数 来定义元数据。
须知:您不应手动在根布局中添加
<head>
标签(如<title>
和<meta>
),而应使用元数据 API (Metadata API),它能自动处理流式传输和去重<head>
元素等高级需求。
在 API 参考 中了解可用的元数据选项。