- 在 Next.js 中有四種方法可以在 routes 之間導航:
- 使用
<Link>
component - 使用
useRouter
hook(用於 Client Components) - 使用
redirect
函數(用於 Server Components) - 使用原生的 History API
- 使用
# Component
<Link>
是一個內建 component,擴展了 HTML 的<a>
tag,提供 routes 之間的 prefetch 和 client-side navigation 功能。- 它是最主要且推薦的 navigation 方式。
- 使用範例:
import Link from "next/link";
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>;
}
# Linking to Dynamic Segments:
- 可以使用 template literals and interpolation
- 範例:
import Link from "next/link";
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
);
}
# Checking Active Links:
- 使用
usePathname()
來檢查當前連結是否活躍,並對應地添加樣式。 - 範例:
"use client";
import { usePathname } from "next/navigation";
import Link from "next/link";
export function Links() {
const pathname = usePathname();
return (
<nav>
<ul>
<li>
<Link
className={`link ${pathname === "/" ? "active" : ""}`}
href="/"
>
Home
</Link>
</li>
<li>
<Link
className={`link ${pathname === "/about" ? "active" : ""}`}
href="/about"
>
About
</Link>
</li>
</ul>
</nav>
);
}
# Scrolling to an id:
- 預設行為是在 navigate 至新路徑時,頁面會滾動到頂部,或者保持滾動位置(在前進或後退時)。
- 可以通過
href
加上#
錨點,或者直接傳遞錨點連結來滾動到特定的id
。 - 範例:
<Link href="/dashboard#settings">Settings</Link>
# Disabling scroll restoration:
- 如果不希望頁面滾動至頂部或保持滾動位置,可以設置
scroll={false}
。 - 範例:
<Link href="/dashboard" scroll={false}>
或使用
Dashboard
</Link>router.push()
:import { useRouter } from "next/navigation";
const router = useRouter();
router.push("/dashboard", { scroll: false });
# useRouter hook
useRouter
允許你在 Client Components 中以 programmatically 更改 routes。- 使用範例:
"use client";
import { useRouter } from "next/navigation";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.push("/dashboard")}>
Dashboard
</button>
);
} - 使用
useRouter
可以 programmatically navigation,適合有特殊需求時使用,否則建議使用 Link
# redirect function
- 在 Server Components 中使用
redirect
函數來進行 navigation。 - 預設情況下,
redirect
返回 307(Temporary Redirect)狀態碼。在 Server Action 中,它會返回 303(See Other)狀態碼,常用於 POST 請求之後重定向到成功頁面。 redirect
會拋出錯誤,因此應避免在try/catch
區塊中調用。- 它也可以用於重定向到外部連結。
- 範例:
import { redirect } from "next/navigation";
async function fetchTeam(id: string) {
const res = await fetch("https://...");
if (!res.ok) return undefined;
return res.json();
}
export default async function Profile({
params,
}: {
params: { id: string };
}) {
const team = await fetchTeam(params.id);
if (!team) {
redirect("/login");
}
}
# Using the native History API
- 使用
window.history.pushState
將新條目添加到瀏覽器歷史記錄中,允許用戶返回到上一個狀態。 - 範例:對商品列表進行排序。
"use client";
import { useSearchParams } from "next/navigation";
export default function SortProducts() {
const searchParams = useSearchParams();
function updateSorting(sortOrder: string) {
const params = new URLSearchParams(searchParams.toString());
params.set("sort", sortOrder);
window.history.pushState(null, "", `?${params.toString()}`);
}
return (
<>
<button onClick={() => updateSorting("asc")}>Sort Ascending</button>
<button onClick={() => updateSorting("desc")}>Sort Descending</button>
</>
);
} - window.history.replaceState:
"use client";
import { usePathname } from "next/navigation";
export function LocaleSwitcher() {
const pathname = usePathname();
function switchLocale(locale: string) {
const newPath = `/${locale}${pathname}`;
window.history.replaceState(null, "", newPath);
}
return (
<>
<button onClick={() => switchLocale("en")}>English</button>
<button onClick={() => switchLocale("fr")}>French</button>
</>
);
} - 用於替換當前瀏覽器歷史記錄條目,無法返回到之前的狀態。
- 範例:切換應用語言。
# How Routing and Navigation Works
- Code Splitting(程式碼拆分):Next.js 自動將程式碼按 route segments 拆分,減少數據傳輸量並提升效能。只有當用戶導航至新的 route 時,才會加載當前 route 所需的程式碼。
- Prefetching(預抓取):
- Prefetch 是背景加載 route 的方式,用於加速 navigation。
- 兩種方式進行 prefetch:
- <Link> component:當 routes 變得可見時,會自動進行 prefetch。預抓取發生在頁面首次加載或滾動進入視窗時。
- router.prefetch():可以 programmatically 使用 useRouter hook 來進行 prefetch。
<Link>
的 default prefetch 行為會根據是否使用loading.js
而有所不同。如果使用了loading.js
,只會預抓取共享的 layout 並緩存 30 秒。- 可以通過設置
prefetch={false}
禁用 prefetch,或者設置prefetch={true}
來 prefetch 完整的頁面數據。 - 注意事項:prefetch 僅在 production 環境中啟用,開發環境不會進行 prefetch。
- Caching(快取):
- Next.js 在客戶端提供一個內存中的快取(Router Cache),用來存儲預抓取的 route segment 和已訪問的 route。
- 在導航過程中,Next.js 會儘量重用快取中的數據,減少對伺服器的請求,提升效能。
- Partial Rendering(部分渲染):
- 部分渲染是指 navigation 時只重新渲染變更的 route segments,而共享的 segments 保持不變。
- 範例:當導航至
/dashboard/settings
和/dashboard/analytics
時,會渲染settings
和analytics
頁面,但共享的dashboard
layout 保持不變。

- Soft Navigation(軟導航):
- 在傳統瀏覽器中,navigation 是 "hard navigation",即頁面重載。而 Next.js 的 App Router 則提供 "soft navigation",即僅重新渲染變更的 route segments,保留客戶端的 React 狀態。
- Back and Forward Navigation:
- 預設情況下,Next.js 會在前進和後退 navigation 時保持滾動位置,並重用 Router Cache 中的 route segments。
- Routing between pages/ 和 app/:
- 當從
pages/
逐步遷移到app/
時,Next.js 會自動處理它們之間的 "hard navigation"。使用幾率檢查方法來檢測 pages/ 和 app/ 之間的轉換,預設誤判幾率為 0.01%,可以在next.config.js
中調整此值。
- 當從