NextJS - Routing - Linking and Navigation

更新於 發佈於 閱讀時間約 14 分鐘
  • 在 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:
      1. <Link> component:當 routes 變得可見時,會自動進行 prefetch。預抓取發生在頁面首次加載或滾動進入視窗時。
      2. 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 保持不變。
raw-image


  • 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 中調整此值。

# 參考

Next.js Documentation

留言
avatar-img
留言分享你的想法!
avatar-img
Learn or Die
0會員
16內容數
分享程式技術
Learn or Die的其他內容
2025/05/05
# Community Starter Kit Support in laravel new 12.2 Laravel new command,新增支援 community starter kit,支援的清單可 參考 laravel new --using statamic/statamic m
2025/05/05
# Community Starter Kit Support in laravel new 12.2 Laravel new command,新增支援 community starter kit,支援的清單可 參考 laravel new --using statamic/statamic m
2025/04/30
# 建立 Routes Next.js 使用基於檔案系統的路由器,資料夾用來定義 routes。 每個資料夾代表一個 route segment,對應到一個 URL segment。 要建立 nested routes,可以將資料夾彼此巢狀。 使用特殊的 page.js 檔案來讓 rou
Thumbnail
2025/04/30
# 建立 Routes Next.js 使用基於檔案系統的路由器,資料夾用來定義 routes。 每個資料夾代表一個 route segment,對應到一個 URL segment。 要建立 nested routes,可以將資料夾彼此巢狀。 使用特殊的 page.js 檔案來讓 rou
Thumbnail
2025/04/27
# Memoized Cache Driver 12.9 新增 memo cache driver,可以對 cache 在做一層 memory cache,比如第一次從 Redis cache 撈,但在同一個 req 當中,之後都可從 PHP Process memory 當中撈 <?php C
2025/04/27
# Memoized Cache Driver 12.9 新增 memo cache driver,可以對 cache 在做一層 memory cache,比如第一次從 Redis cache 撈,但在同一個 req 當中,之後都可從 PHP Process memory 當中撈 <?php C
看更多
你可能也想看
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
這篇文章介紹了網站的整體架構以及開發時所使用的工具和套件,包括 Next.js、Tailwind CSS 和 socket.io 等。文章回顧了程式碼的重構與優化,幫助開發者提高工作效率,適合希望深入瞭解前端開發和網站架構的讀者。
Thumbnail
這篇文章介紹了網站的整體架構以及開發時所使用的工具和套件,包括 Next.js、Tailwind CSS 和 socket.io 等。文章回顧了程式碼的重構與優化,幫助開發者提高工作效率,適合希望深入瞭解前端開發和網站架構的讀者。
Thumbnail
※ 原本狀態:伺服器渲染 這是 MVC 架構下的 request / response 示意圖,在這張圖呈現的架構裡,畫面和資料都由同一個架構處理。 伺服器渲染流程: 瀏覽器針對特定網址送出請求。 路由器解析請求後,轉接給對應的 controller。 controller 按照要求,透過
Thumbnail
※ 原本狀態:伺服器渲染 這是 MVC 架構下的 request / response 示意圖,在這張圖呈現的架構裡,畫面和資料都由同一個架構處理。 伺服器渲染流程: 瀏覽器針對特定網址送出請求。 路由器解析請求後,轉接給對應的 controller。 controller 按照要求,透過
Thumbnail
這次要講的是 $route 及 $router 的區別,看似相似的兩個東西,其實應用時機也大不相同,以下以簡單的幾個例子舉例。
Thumbnail
這次要講的是 $route 及 $router 的區別,看似相似的兩個東西,其實應用時機也大不相同,以下以簡單的幾個例子舉例。
Thumbnail
在程式任何地方都能修改各種react組件狀態的做法分享
Thumbnail
在程式任何地方都能修改各種react組件狀態的做法分享
Thumbnail
Vue Router 動態路由,假設有一個賣場,裡面有 100 個商品,我們不可能針對它們創 100 對應的路由,因此我們需要一個動態路由,利用"路徑帶參數"的方式來撈取商品的資訊。
Thumbnail
Vue Router 動態路由,假設有一個賣場,裡面有 100 個商品,我們不可能針對它們創 100 對應的路由,因此我們需要一個動態路由,利用"路徑帶參數"的方式來撈取商品的資訊。
Thumbnail
本篇文章介紹了路徑的概念和兩種不同的路徑運用。這些知識對於網頁開發非常重要,能夠幫助網站開發者更好地管理資源文件的位置。文章通過實際例子和相對路徑的範例來解釋這些概念。希望通過這篇文章,讀者能夠清楚地瞭解路徑的概念,並在日後的開發中能夠靈活運用。
Thumbnail
本篇文章介紹了路徑的概念和兩種不同的路徑運用。這些知識對於網頁開發非常重要,能夠幫助網站開發者更好地管理資源文件的位置。文章通過實際例子和相對路徑的範例來解釋這些概念。希望通過這篇文章,讀者能夠清楚地瞭解路徑的概念,並在日後的開發中能夠靈活運用。
Thumbnail
JavaScript 套件,頁碼 Pagination.js 搭配 axios API 請求範例
Thumbnail
JavaScript 套件,頁碼 Pagination.js 搭配 axios API 請求範例
Thumbnail
前言 現在的前端需求已經越來越高,要考慮HTML及CSS的切版美觀程度,以及React以及Flutter所提出的元件(Componet、widget)觀念,也就是將元件模組化,使元件可以更動態的被程式運行,而不用靜態的客製化每一個介面。開發一個好的元件可以提升整體的開發速度,讓任何使用元件的開發者
Thumbnail
前言 現在的前端需求已經越來越高,要考慮HTML及CSS的切版美觀程度,以及React以及Flutter所提出的元件(Componet、widget)觀念,也就是將元件模組化,使元件可以更動態的被程式運行,而不用靜態的客製化每一個介面。開發一個好的元件可以提升整體的開發速度,讓任何使用元件的開發者
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News