基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

App Router 中的 layout.js、page.js 和 template.js 的区别

知识点图片

在 Next.js App Router 中,page.jslayout.jstemplate.js 是构建路由和 UI 的三个核心文件。

简单来说:

  • page.js内容(特定路由的 UI)。
  • layout.js框架(共享 UI,状态保留,不重新渲染)。
  • template.js特殊框架(共享 UI,状态重置,每次导航都会重新渲染)。

下面是详细的区别解析:


1. page.js (页面)

这是路由的叶子节点。它是特定 URL 路径下实际显示的 UI 内容。

  • 作用:定义特定路由的 UI。
  • 特性
    • 每个文件夹(路由段)必须有一个 page.js 才能使该路径可访问。
    • 它可以接收 params (路径参数) 和 searchParams (查询参数)。
  • 生命周期:当你访问该路由时渲染。

2. layout.js (布局)

这是共享 UI,用于包裹多个页面。

  • 作用:在多个路由之间共享 UI(如导航栏、侧边栏、页脚)。
  • 特性(核心区别)
    • 状态持久化 (Persists State):当在同一布局下的不同页面之间导航时,Layout 不会重新挂载(Remount)。这意味着组件的状态(如输入框的值、滚动位置)会保持不变。
    • 高性能:因为不重新渲染,切换页面时只更新变化的部分(即 Page 内容),交互更流畅。
    • 嵌套:Layout 可以嵌套(父路由的 Layout 包裹子路由的 Layout)。
  • 典型场景:全局导航栏、Sidebar、全局 Context Provider。

3. template.js (模板)

这就有点像 layout.js 的孪生兄弟,但有一个关键区别。

  • 作用:也是用于包裹页面和子布局的共享 UI。
  • 特性(核心区别)
    • 创建新实例 (Creates a new instance):当在共享同一个 Template 的路由之间导航时,Template 会卸载旧实例并挂载新实例。
    • 状态重置:这意味着 DOM 元素会重新创建,状态(State)会丢失useEffect 会重新执行。
  • 典型场景
    • 进入/退出动画(如使用 Framer Motion,每次切换页面都需要触发动画)。
    • 依赖于 useEffect 的页面记录(如每次进入页面都要发送埋点数据)。
    • 重置状态(如切换页面时希望重置表单数据)。

核心对比:Layout vs Template

这是最容易混淆的地方。假设你有一个计数器组件 Counter

特性 Layout (layout.js) Template (template.js)
导航行为 路由切换时,组件保持不动 路由切换时,组件销毁并重建
State (状态) 保留 (计数器数字不变) 重置 (计数器归零)
DOM 不更新 (除非 Props 变了) 重新创建 DOM 节点
useEffect 仅在首次加载时触发 每次路由切换都触发
主要用途 导航栏、页脚、持久化播放器 页面转场动画、埋点统计

渲染层级结构

Next.js 在渲染时,会将它们按照以下顺序嵌套:

jsx
<Layout>
  <Template>
    <ErrorBoundary> {/* error.js */}
      <Suspense>    {/* loading.js */}
        <Page />
      </Suspense>
    </ErrorBoundary>
  </Template>
</Layout>

注意Template 是被包裹在 Layout 内部,但在 Page 外部的。


代码示例

假设文件结构如下:

plaintext
app/
  dashboard/
    layout.js
    template.js
    page.js
    settings/
      page.js

当你从 /dashboard 跳转到 /dashboard/settings 时:

  1. app/dashboard/layout.js:
    • ⛔️ 不会 重新渲染。
    • ✅ 其中的 <input> 输入内容会保留。
  2. app/dashboard/template.js:
    • 🔄 重新挂载。
    • ❌ 其中的 useState 状态会重置。
    • ✨ 如果写了 CSS 动画,动画会重新播放。
  3. app/dashboard/page.js (旧页面):
    • 🗑 被卸载。
  4. app/dashboard/settings/page.js (新页面):
    • 🆕 被挂载。

总结建议

  • 默认使用 layout.js。99% 的情况下,你想要的是布局(保留导航栏状态,减少重绘)。
  • 仅在需要特定行为时使用 template.js。比如你需要每次切换页面都触发淡入淡出动画,或者你需要确保每次切换页面时某个组件的状态都被清空。
00:00
00:00