連結與導航
在 Next.js 中有四種方式可以在路由之間進行導航:
- 使用
<Link>
元件 - 使用
useRouter
鉤子 (客戶端元件) - 使用
redirect
函式 (伺服器元件) - 使用原生的 History API
本頁將介紹如何使用這些選項,並深入探討導航的運作原理。
<Link>
元件
<Link>
是一個內建元件,它擴展了 HTML 的 <a>
標籤,提供 預取 (prefetching) 和客戶端路由導航功能。這是 Next.js 中主要且推薦的路由導航方式。
你可以從 next/link
導入它,並將 href
屬性傳遞給元件:
你還可以傳遞其他可選屬性給 <Link>
。詳見 API 參考文件。
範例
連結到動態區段
當連結到 動態區段 時,你可以使用 模板字面量和插值 來生成連結列表。例如,生成部落格文章列表:
檢查當前活動連結
你可以使用 usePathname()
來判斷連結是否處於活動狀態。例如,為活動連結添加類別時,可以檢查當前的 pathname
是否與連結的 href
相符:
滾動到特定 id
Next.js App Router 的預設行為是 在導航到新路由時滾動到頁面頂部,或在向前/向後導航時保持滾動位置。
如果你想在導航時滾動到特定的 id
,可以在 URL 後附加 #
哈希連結,或直接將哈希連結傳遞給 href
屬性。這是因為 <Link>
會渲染為 <a>
元素。
須知:
- 如果頁面在導航時不在視窗的可見範圍內,Next.js 會滾動到 頁面。
禁用滾動恢復
Next.js App Router 的預設行為是 在導航到新路由時滾動到頁面頂部,或在向前/向後導航時保持滾動位置。如果你想禁用此行為,可以將 scroll={false}
傳遞給 <Link>
元件,或在 router.push()
或 router.replace()
中設定 scroll: false
。
useRouter()
鉤子
useRouter
鉤子允許你從 客戶端元件 中以程式方式變更路由。
完整的 useRouter
方法列表,請參閱 API 參考文件。
建議:除非有特定需求,否則請使用
<Link>
元件在路由之間導航。
redirect
函式
對於 伺服器元件,請改用 redirect
函式。
須知:
redirect
預設返回 307 (臨時重定向) 狀態碼。在伺服器動作中使用時,它會返回 303 (查看其他),這通常用於在 POST 請求後重定向到成功頁面。redirect
內部會拋出錯誤,因此應在try/catch
區塊外呼叫。redirect
可以在渲染過程中的客戶端元件呼叫,但不能在事件處理程序中呼叫。你可以改用useRouter
鉤子。redirect
也接受絕對 URL,可用於重定向到外部連結。- 如果你想在渲染過程之前進行重定向,請使用
next.config.js
或 中介軟體。
更多資訊請參閱 redirect
API 參考文件。
使用原生 History API
Next.js 允許你使用原生的 window.history.pushState
和 window.history.replaceState
方法來更新瀏覽器的歷史堆疊,而無需重新載入頁面。
pushState
和 replaceState
呼叫會與 Next.js 路由器整合,讓你與 usePathname
和 useSearchParams
同步。
window.history.pushState
使用它來新增一個新條目到瀏覽器的歷史堆疊中。使用者可以導航回到先前的狀態。例如,對產品列表進行排序:
window.history.replaceState
使用它來替換瀏覽器歷史堆疊中的當前條目。使用者無法導航回到先前的狀態。例如,切換應用程式的語言:
路由與導航的運作原理
App Router 使用混合方法進行路由和導航。在伺服器端,你的應用程式程式碼會根據路由區段自動進行 程式碼分割 (code splitting)。在客戶端,Next.js 會 預取 (prefetch) 並 快取 (cache) 路由區段。這意味著,當使用者導航到新路由時,瀏覽器不會重新載入頁面,只有變更的路由區段會重新渲染 — 從而提升導航體驗和效能。
1. 程式碼分割
程式碼分割允許你將應用程式程式碼拆分為較小的套件,供瀏覽器下載和執行。這減少了每個請求傳輸的資料量和執行時間,從而提升效能。
伺服器元件 讓你的應用程式程式碼能根據路由區段自動進行程式碼分割。這意味著導航時只會載入當前路由所需的程式碼。
2. 預取
預取是一種在使用者訪問路由前,在背景預先載入路由的方式。
Next.js 中有兩種預取路由的方式:
<Link>
元件:當路由在使用者的視窗中可見時,會自動進行預取。預取會在頁面首次載入或通過滾動進入視窗時觸發。router.prefetch()
:可以使用useRouter
鉤子以程式方式預取路由。
<Link>
的預設預取行為(即未指定 prefetch
屬性或設為 null
)會根據 loading.js
的使用情況而有所不同。只有共享的佈局,直到第一個 loading.js
文件的渲染「樹」中的元件會被預取並快取 30s
。這減少了獲取整個動態路由的成本,意味著你可以顯示 即時載入狀態,為使用者提供更好的視覺反饋。
你可以通過將 prefetch
屬性設為 false
來禁用預取。或者,你也可以通過將 prefetch
屬性設為 true
來預取超出載入邊界的完整頁面資料。
更多資訊請參閱 <Link>
API 參考文件。
須知:
- 預取功能僅在生產環境中啟用,開發環境中不啟用。
3. 快取
Next.js 有一個稱為 路由器快取 (Router Cache) 的 記憶體客戶端快取。當使用者在應用程式中導航時,預取 的路由區段和已訪問路由的 React 伺服器元件負載會被儲存在快取中。
這意味著在導航時,會盡可能重用快取,而不是向伺服器發送新請求 — 通過減少請求和傳輸的資料量來提升效能。
了解更多關於 路由器快取 的運作方式和如何配置它。
4. 部分渲染
部分渲染意味著在導航時,只有變更的路由區段會在客戶端重新渲染,任何共享的區段會被保留。
例如,在兩個兄弟路由 /dashboard/settings
和 /dashboard/analytics
之間導航時,settings
和 analytics
頁面會被渲染,而共享的 dashboard
佈局會被保留。

如果沒有部分渲染,每次導航都會導致客戶端重新渲染整個頁面。僅渲染變更的區段減少了傳輸的資料量和執行時間,從而提升效能。
5. 軟導航
瀏覽器在頁面之間導航時會執行「硬導航」。Next.js App Router 實現了頁面之間的「軟導航」,確保只有變更的路由區段會重新渲染(部分渲染)。這使得客戶端的 React 狀態在導航時得以保留。
6. 向後和向前導航
預設情況下,Next.js 會在向後和向前導航時保持滾動位置,並重用 路由器快取 中的路由區段。
7. 在 pages/
和 app/
之間的路由
當從 pages/
逐步遷移到 app/
時,Next.js 路由器會自動處理兩者之間的硬導航。為了檢測從 pages/
到 app/
的過渡,有一個客戶端路由器過濾器,它利用對應用路由的概率檢查,偶爾會導致誤判。預設情況下,這種情況應該非常罕見,因為我們將誤判概率配置為 0.01%。這個概率可以通過 next.config.js
中的 experimental.clientRouterFilterAllowedRate
選項進行自訂。需要注意的是,降低誤判率會增加客戶端套件中生成的過濾器的大小。
另外,如果你希望完全禁用此處理並手動管理 pages/
和 app/
之間的路由,可以在 next.config.js
中將 experimental.clientRouterFilter
設為 false。當此功能被禁用時,任何與應用路由重疊的頁面動態路由預設將無法正確導航。