Next.js 中的新应用程序路由器引入了两种用于构建 UI 的新文件约定:Layouts
和 Templates
。这些可以用来组织网页、跟踪更改并使网站运行得更快。
在开发中容易混淆使用模板和布局,而忽略了它们之间的用例和区别。本篇文章将以浅显易懂的方式阐述 Layouts
和 Templates
的区别,如何进行设置,并推荐适合使用它们的最佳场景。
深入理解 Layouts 与 Templates
在 Next.js 中,Layouts
像是持久的 UI 外壳,将应用的各个页面紧紧包裹,是一种将整个应用程序中多个页面共同的 UI 抽象为组件的方式,例如,像页脚这样的 UI 元素可能在整个应用程序中重复出现。Layouts
允许开发者设定一种在不同路由间保持完整的、统一的、无需再次渲染的通用结构。对于如 Header
、Footer
以及侧边栏这类需要在用户浏览应用过程中保持一致的组件来说,这特别实用。
- 在共享相同布局的不同页面之间导航时,布局组件不会重新渲染。
- 导航时,布局中的状态仍将被保留并保持完全交互。
模板和布局是同义词,都是在多个页面上重复出现的共享 UI。但有一项关键的不同:每当用户跳转至新的页面时,模板都会全新地挂载一次。这个重新挂载的过程将重置所有的组件状态和效果,使每一次页面的过渡都能有一个全新的起点。
- 布局在路由之间导航时保留状态,不会重新渲染。
- 模板不同,它们在页面路由之间导航时重新渲染,并为每个子元素创建新实例。
如何定义 Layouts 和 Templates
如果要定义一个 layout
,需要在一个名为 layout.js
或 layout.tsx
的文件中创建一个 React 组件。这个组件应包含一个 children
属性,可以将子 layout
或者页面整合到一起。
以下是一个简单的 layout
组件示例:
javascript
// app/layout.tsx
import Header from "./Header";
import Footer from "./Footer";
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<Header />
{children}
<Footer />
</div>
);
}
模板 Template
的定义是通过在一个名为 template.js
或 template.tsx
的文件中导出一个默认的 React 组件来实现的。与 layout
类似,该组件也应能接收并渲染 children
属性。
以下是一个简单的 template
组件示例:
javascript
// app/template.tsx
"use client";
import { useEffect } from "react";
export default function Template({ children }: { children: React.ReactNode }) {
useEffect(() => {
console.log("Log page view");
}, []);
return <div>{children}</div>;
}
小提示:一个单独的路由可以包含布局和模板,其中布局充当外部外壳,将模板包裹在其中。
组件重新挂载:布局与模板
考虑一个最简单的示例,展示在使用布局和模板时组件重新挂载的情况。首先使用 create-next-app
创建并初始化一个 Next.js 项目。
初始化身份验证界面
在 app
文件夹下创建目录 auth
。
在 auth
目录下,添加 login
的子目录,在其中添加一个文件 page.tsx
来构建登录页面:
javascript
export default function RegisterPage() {
return <h1>Register</h1>;
}
实现共享布局
在目录 auth
下,创建一个文件 layout.tsx
,其中包含用户反馈输入和导航链接:
javascript
"use client";
import Link from "next/link";
import { useState } from "react";
export default function AuthLayout({ children }) {
const [feedback, setFeedback] = useState("");
return (
<div>
<label htmlFor="feedback">Your UX Feedback</label>
<input
id="feedback"
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
/>
<nav>
<Link href="/auth/login">Login</Link>
<Link href="/auth/register">Register</Link>
</nav>
{children}
</div>
);
}
在登录和注册路由之间切换,并观察反馈输入框的状态是否得以保留。
布局到模板
将文件名从 layout.tsx
更改为 template.tsx
。此更改意味着在登录和注册页面之间切换时,反馈输入的状态会被重置,表明组件在每次路由更改时都会重新加载。
在布局和模板之间做决策
在开发 Web 应用程序时,将不可避免地需要在布局和模板之间做出选择。下面是一些建议,希望可以帮助做出明智的决策:
选择布局时
- 保证一致性:通过使用布局,在整个应用程序中提供统一的外观和行为。它们非常适合用于诸如页眉和页脚之类的常见元素。
- 维护状态:布局有助于保持状态和行为的持续性,例如用户登录状态,在导航过程中保持不变。
- 提高性能:通过最小化重渲染和简化状态管理,布局有助于提升性能。
选择模板时
- 隔离性:当组件不应共享状态或行为时,模板是有用的,因为它们在导航时会重新加载和重新渲染。
- 行为灵活性 :如果需要在用户导航到组件时触发特定效果或状态更改,模板提供了这种功能。例如,它们适用于:
- 使用 useEffect 跟踪页面浏览量。
- 使用 useState 管理的每个页面独立的反馈表单。
- 修改默认行为:模板可以修改某些功能在框架内的工作方式。例如,它们可以控制在页面转换期间在 Suspense 边界中显示备用 UI,而布局无法实现。
总之,对于页面中的静态和一致元素,首选布局以获得性能和状态管理方面的优势。而模板则适用于创建独立、与状态无关的组件实例,在每次导航时都能发挥效果和状态初始化功能。
总结
总的来说,Next.js 的布局和模板为 UI 构建提供了不同的方法:
- 布局提供了一个稳定的 UI 框架,减少重新渲染并在导航过程中保持状态,非常适合一致的整站组件。
- 相比之下,模板在每次访问页面时重置状态并重新渲染,适用于独特的、页面特定的行为。
在 Next.js 应用程序中,为了效率和一致性,选择布局 layout
;而对于需要独立、与状态无关的组件,在导航时需要新鲜状态的情况,选择模板 template
。正确的选择取决于每个页面在 Next.js 应用程序中的具体需求,平衡用户体验和性能。