布局和模版
特殊文件layout.js 和 template.js 让您创建可在 路由间共享的 UI。本页面将知道您如何及何时使用这些特殊文件。
布局
布局是在多个路由间共享的 UI。在导航是,布局保留状态,保持交互性并且不会重新渲染。也可以嵌套布局。
您能够通过在layout.js文件中默认输出一个 React 组件来定义一个布局。该组件应该接收一个children属性,用作在渲染过程中填充子布局或页面。
例如,以下布局将会被/dashboard 和 /dashboard/settings 页面共享。
export default function DashboardLayout({
children, // will be a page or nested layout
}: {
children: React.ReactNode,
}) {
return (
<section>
{/* Include shared UI here e.g. a header or sidebar */}
<nav></nav>
{children}
</section>
);
}
根布局 (必须)
根布局在顶层定义并应用于所有路由。此布局是必须得并且必须包含html 和 body标签,允许您修改由服务器返回的初始化 HTML。
export default function RootLayout({
children,
}: {
children: React.ReactNode,
}) {
return (
<html lang="en">
<body>
{/* Layout UI */}
<main>{children}</main>
</body>
</html>
);
}
嵌套布局
默认情况下, 文件夹层次结构中的布局是可嵌套的, 这代表其通过children属性包裹子布局。您可以在特定的路由段(文件夹)中通过添加layout.js文件来嵌套布局。
例如,在dashboard文件夹中新建一个layout.js文件来创建/dashboard路由的布局。
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return <section>{children}</section>;
}
export default function DashboardLayout({ children }) {
return <section>{children}</section>;
}
如果您要合并上面的两个布局, 根布局 (app/layout.js) 将会包裹 dashboard 布局 (app/dashboard/layout.js), 从而生成 app/dashboard/*路由段.
这两个布局将这样嵌套:
您需要知道:
- 布局能够使用
.js,.jsx, or.tsx文件扩展名。- 只有根布局能够包含
<html>和<body>标签。- 当在同一文件夹下定义一个
layout.js文件和一个page.js文件时, layout 将会包裹 page。- 默认情况下,布局是 服务器端组件 ,但是能够设置为客户端组件.
- 布局能够获取数据。查看数据获取 部分来了解更多。
- 不能再父子布局间传递数据。不过,您可以在路由中多次获取相同的数据,并且 React 会 自动清除重复数据请求而不会影响性能。
- 布局无法访问
pathname(了解更多). 但是引入的客户端组件能够通过usePathnamehook 访问 pathname。- 布局无法访问其下方的路由段。您可以在客户端组件中使用
useSelectedLayoutSegment或useSelectedLayoutSegments来访问所有路由段。- 您能够使用路由组来选择共享布局中的具体路由段。
- 您你能够使用路由组来创建多个根布局.查看示例.
模版
模版在包裹子布局或页面方面与布局类似。不同于布局在跨路由中持续保持状态,模版在导航时为它们的每个子项创建了新的实力。这意味着用户在共享模版的路由间导航时,会挂载一个新的子实例,重新创建 DOM 元素,客户端组件不会保留状态并重新同步效果。
也许有些情况下,你需要这些特定行为,并且模版会是相对于布局更为适合的选择。例如:
- 导航时重新同步
useEffect。 - 导航时重置子客户端组件的状态。
模版可能通过在一个template.js文件中导出一个默认 React 组件来定义。且组件应该接收一个children属性。
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>;
}
export default function Template({ children }) {
return <div>{children}</div>;
}
就嵌套而言, template.js在父子布局间呈现。下列是一个简化的输出:
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>
例子
Metadata
您能够使用Metadata APIs修改 HTML 元素<head>,如:title 和 meta。
Metadaya 能够由在 layout.js 或 page.js文件中输出metadata 对象 或 generateMetadata function来定义。
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Next.js",
};
export default function Page() {
return "...";
}
export const metadata = {
title: "Next.js",
};
export default function Page() {
return "...";
}
您需要知道: 您不应该在根布局中手动添加
<head>标签,如:<title>和<meta>。 相反, 使用自动处理高级需求的Metadata API,如:流式处理和重复数据删除<head>元素.
在API reference了解更多关于可用的 metadata 选项。
Active 导航链接
您可以使用usePathname() hook 来决定是否导航链接处于活动状态。
因为 usePathname()