Next.js Layouts 與 Templates
在構建應用程式時,導航欄、側邊欄或頁腳通常是多個頁面共用的。Next.js 提供了 Layouts 和 Templates 兩種檔案慣例來處理這些共享 UI。
Layouts (佈局)
Layout 是指在多個路由之間共享的 UI。當使用者在子路由之間導航時,Layout 會被保留,不會重新渲染 (Re-render),這使得它非常適合存放導航列或搜尋框,因為它能保留輸入框內容或捲動位置。
如何定義 Layout?
在任何路由目錄下建立 layout.tsx,該佈局將自動應用於該目錄及其所有子目錄。
// app/dashboard/layout.tsx
export default function DashboardLayout({
children, // 代表子頁面或子佈局
}: {
children: React.ReactNode;
}) {
return (
<section className="flex">
<nav className="w-64 bg-gray-100 p-4">
{/* 指向 /dashboard, /dashboard/settings 等 */}
<ul>
<li>首頁</li>
<li>設定</li>
</ul>
</nav>
<div className="flex-1 p-8">{children}</div>
</section>
);
}
Layout 的特性:
- 狀態保留:導覽時不會丟失 React State。
- 巢狀結構:子目錄的 Layout 會被包在父目錄的 Layout 裡面。
- 不支援重新載入動畫:因為它不會重新掛載,所以 CSS 動畫可能不會重複播放。
Templates (模板)
Template 的功能與 Layout 類似,但他有一個核心差異:當使用者切換路由時,Template 會為每個子路由建立一個全新的實例。
這意味著當你在路由之間導航時:
- DOM 元素會被重新建立。
- 狀態 (State) 不會被保留。
- Effects 會重新執行。
為什麼需要 Template?
通常在以下特定場景,你會選擇使用 Template 而非 Layout:
- CSS 動畫:如果你希望每次切換頁面時都有進場動畫 (Enter/Exit animations)。
- useEffect 依賴:當你需要在導航時重置某些追蹤邏輯或重新訂閱。
如何使用 Template?
檔名必須為 template.tsx:
// app/dashboard/template.tsx
'use client';
import { useEffect } from 'react';
export default function Template({ children }: { children: React.ReactNode }) {
useEffect(() => {
console.log('頁面已切換,Template 重新初始化');
}, []);
return <div>{children}</div>;
}
Layout 與 Template 並存時的行為
你可能會好奇,如果在同一個資料夾下同時建立了 layout.tsx 和 template.tsx,它們會如何運作?
答案是:它們可以共存,且有固定的包裹順序。
當兩者同時存在時,Next.js 會將 Template 包裹在 Layout 裡面,結構如下:
<Layout>
<Template>
{/* Page 內容 */}
<Page />
</Template>
</Layout>
這意味著:
- Layout 負責「持久化」:最外層的 UI (Layout) 在導航時保持不變,狀態保留。
- Template 負責「重置」:內層的 UI (Template) 在每次導航時都會重新建立。
這種模式非常實用。例如,你可以使用 layout.tsx 來放置不會變動的側邊欄導航,同時使用 template.tsx 來包裹頁面內容,以便在每次切換頁面時觸發淡入淡出 (Fade-in) 的動畫效果。
Layout vs Template 比較
| 特性 | Layout | Template |
|---|---|---|
| 重新渲染 | 導覽時不重新渲染 | 導覽時重新掛載 (Re-mount) |
| 狀態保留 | 是 (保留內容、捲動位置) | 否 (狀態被重置) |
| 效能 | 較佳 | 效能略遜 (因需重建 DOM) |
| 適用場景 | 大部分共享 UI | 進場動畫、重置狀態 |
總結
在 Next.js 中,預設情況下你應該始終使用 Layout。只有當你明確需要「每次導覽都重置狀態」或「每次都要播放動畫」時,才考慮使用 Template。
這種精細的控制讓你在開發時,能根據效能與使用者體驗做出最佳的設計抉擇。