iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Modern Web

30 天淺入淺出 Next.js 13系列 第 12

Day12 - 導航(Linking & Navigating)

  • 分享至 

  • xImage
  •  

今天來介紹如何在 Next 路由導航,有兩種方式:

  • Link component
  • useRouter hook

這兩個都是 Next 提供的功能,兩個基本上有著相同的功能,差別在於使用方式不一樣。
Link component 提供一個實際的 tag 供使用者點按,useRouter 則是可以利用程式去控制 router 的跳轉功能。

最後會講到 Next 的路由導航運作方式 -> 這個才是重點呀,看看 Next 在背後都幫我們做掉了哪些事。

大綱

  • <Link> Component
  • useRouter hook
  • 導航運作機制

Link Component

<Link> 是 Next 提供的組件,它繼承了 HTML 的 <a> tag,並且提供了軟導航(soft navigating)與預取(prefeching)的功能。

<Link> 組件可以使用在 server component 與 client component 上。

soft navigating 與 prefetching 最後一章會提到

使用方式

import Link from 'next/link'
 
export default function Page() {
  const path = '/about'    
  return (
      <>
          // 1. 導航到 /dashboard
          <Link href="/dashboard">Dashboard</Link>
          // 2. 使用樣板字串符也是完全沒問題滴
          <Link href={`${path}`}>About</Link>
      </>
  )
}

useRouter hook

useRouter 可以讓我們使用程式的方式做路由導航,適合用在我們想主動轉換導航,或是我們不想渲染出 <a> tag 的時候。

因為是 react hook,所以只能 useRouter 運行在 client component 上。

'use client'
 
import { useRouter } from 'next/navigation'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

導航運作機制

在開始講運作機制之前,先來了解一下 server 與 client 不同的導航策略。

server

next 會依據每個 route 自動把 code 做切分,當使用者訪問時可以只執行該頁所需要的 code。

client

client 端會利用 prefetch 與 cache 的方式加速訪問頁面的速度,並且只渲染有差異的部分。


OK~現在正式進入導航運作機制的部分

1. prefetching

prefetching 就是在我們尚未訪問頁面以前,Next 就已經提前將頁面的資料給載入了。

有兩種方式讓 Next 做到 prefetching

  • <Link> 進入到視窗時
  • 使用 useRouterprefetch() method

因為 useRouter 的關係,底下先以 client component 演示。Link component 也可以在 server component 運行。

// in client component
'use client'

export default Page() {
    // 1. 使用 useRouter,prefetch '/dashboard' 
    const router = useRouter;
    router.pretch('/dashboard'); 
    
    return (
        // 2. 當 Link 組件進入到頁面可視範圍時,prefetch '/dashboard'
        <Link href='/dashboard' />
    )
}

有人可能會好奇 prefetch 回來的資料是什麼?
這些資料是RSC Payload
裡面包含了 server component 的渲染資訊、傳給 client component 的 props 與 client component placeholder,詳細的資訊可以操考官方文章

route 差異

prefetch 就是預先跟 server 要接下來會訪問到的頁面資料,但有些路由包含動態內容,提前取得頁面內容有可能會導致內容偏誤。

所以 Next 對於靜態與動態的 routes 有不一樣的 prefetch 策略。

這裡講的動態 routes 是指「顯示的內容」是動態的,並不是指「訪問的路徑」是動態的。
關於如何判斷路由是否為動態可以參考 Day9 - Server Component - Next13 的渲染策略一文

  • 靜態渲染頁面:直接整頁 cache
  • 動態渲染頁面:它只會幫你快取 layout.tsx 的 UI 還有第一個 loading.tsx 的 UI,而且只會幫你保留 30 秒

取消 prefetch

我們也可以取消 prefetch 這個功能,只要在 <Link> 組件上傳入 prefetch: false

export default Page() {    
    return (
        // 不自動 prefetch 頁面
        <Link 
            href='/dashboard' 
            prefetch={false}
        />
    )
}

2. Caching

Next 在 client 端有一個特殊的 cache 機制,可以把我們每個訪問過或 prefetch 過的頁面資料存起來。

當我們再次訪問時就可以渲染 cache 的結果,無需再跟 server 發送請求。

這跟 Day9 - Server Component 那章提到的 server-level cache 不一樣。路由的 cache 是存放在 client 端暫存記憶體當中。

底下是使用 router cache 的示意圖:

因為這些 cache 是存放在暫存記憶體當中,所以在我們按下重新整理或是關閉頁面後開起來,這份 cache 就沒了。

此外,Next 還有設定每個路由的 cache 時長,如果超過時間也會自動清除:

  • 靜態渲染路由:5 分鐘
  • 動態渲染路由:30 秒

3. 部分渲染

當路由切換時,若兩個頁面都有用到相同的 layout.tsx UI,那這個 layout.tsx UI 是不會重新渲染的,只會渲染差異的部分。

事實上,若兩頁共享了同一個 layout.tsx UI,client 連這份 layout.tsx 的請求都不會發,因為它會直接使用 cache 的資料。

這有兩個好處:

  1. server 少了額外渲染 layout.tsx 的負擔
  2. 減少傳輸的資料量

4. 軟導航(Soft Navigation)

<Link>useRouter 提供的都是軟導航(soft navigation),使用軟導航的好處就是可以保留頁面原本的狀態,舉凡 react 的狀態、dom focus 的狀態,這些都會保留下來。

而 browser 提供的 <a> 是硬導航(hard navigation),代表路由在切換的時候,整個頁面都會 reload,前一頁的所有狀態都會消失,包含 router cache,因為 cache 也是存在暫存記憶體當中。

這誰扛得住?

其他特性

Next 的路由系統還會幫我們記憶 scroll 的位置。

參考資料


上一篇
Day11 - Component Composition Pattern
下一篇
Day13 - Routes Group 幫你的路由創個群組吧
系列文
30 天淺入淺出 Next.js 1321
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言