useLinkStatus

useLinkStatus 鉤子可讓您追蹤 <Link>pending 狀態。您可以使用它在使用者導航到新路由時顯示內嵌的視覺回饋(例如旋轉圖示或文字閃爍)。

useLinkStatus 在以下情況特別有用:

  • 預取 (Prefetching) 被禁用或正在進行中,導致導航被阻擋
  • 目標路由是動態路由 沒有包含 loading.js 檔案來實現即時導航
'use client'

import { useLinkStatus } from 'next/link'

export default function LoadingIndicator() {
  const { pending } = useLinkStatus()
  return pending ? (
    <div role="status" aria-label="Loading" className="spinner" />
  ) : null
}
'use client'

import { useLinkStatus } from 'next/link'

export default function LoadingIndicator() {
  const { pending } = useLinkStatus()
  return pending ? (
    <div role="status" aria-label="Loading" className="spinner" />
  ) : null
}
import Link from 'next/link'
import LoadingIndicator from './loading-indicator'

export default function Header() {
  return (
    <header>
      <Link href="/dashboard" prefetch={false}>
        Dashboard <LoadingIndicator />
      </Link>
    </header>
  )
}
import Link from 'next/link'
import LoadingIndicator from './loading-indicator'

export default function Header() {
  return (
    <header>
      <Link href="/dashboard" prefetch={false}>
        Dashboard <LoadingIndicator />
      </Link>
    </header>
  )
}

重要須知:

  • useLinkStatus 必須在 Link 元件的子元件中使用
  • Link 元件設定 prefetch={false} 時,此鉤子最為有用
  • 如果連結路由已被預取,pending 狀態將被跳過
  • 當快速連續點擊多個連結時,只會顯示最後一個連結的 pending 狀態
  • 此鉤子在 Pages Router 中不受支援,將始終返回 { pending: false }

參數

const { pending } = useLinkStatus()

useLinkStatus 不接受任何參數。

返回值

useLinkStatus 返回一個包含單一屬性的物件:

屬性類型描述
pendingboolean歷史更新前為 true,更新後為 false

範例

內嵌載入指示器

當使用者在預取完成前點擊連結時,添加視覺回饋有助於提示導航正在進行中。

'use client'

import { useLinkStatus } from 'next/link'

export default function LoadingIndicator() {
  const { pending } = useLinkStatus()
  return pending ? (
    <div role="status" aria-label="Loading" className="spinner" />
  ) : null
}
'use client'

import { useLinkStatus } from 'next/link'

export default function LoadingIndicator() {
  const { pending } = useLinkStatus()
  return pending ? (
    <div role="status" aria-label="Loading" className="spinner" />
  ) : null
}
import Link from 'next/link'
import LoadingIndicator from './components/loading-indicator'

const links = [
  { href: '/shop/electronics', label: 'Electronics' },
  { href: '/shop/clothing', label: 'Clothing' },
  { href: '/shop/books', label: 'Books' },
]

function Menubar() {
  return (
    <div>
      {links.map((link) => (
        <Link key={link.label} href={link.href}>
          {link.label} <LoadingIndicator />
        </Link>
      ))}
    </div>
  )
}

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div>
      <Menubar />
      {children}
    </div>
  )
}
import Link from 'next/link'
import LoadingIndicator from './components/loading-indicator'

const links = [
  { href: '/shop/electronics', label: 'Electronics' },
  { href: '/shop/clothing', label: 'Clothing' },
  { href: '/shop/books', label: 'Books' },
]

function Menubar() {
  return (
    <div>
      {links.map((link) => (
        <Link key={link.label} href={link.href}>
          {link.label} <LoadingIndicator />
        </Link>
      ))}
    </div>
  )
}

export default function Layout({ children }) {
  return (
    <div>
      <Menubar />
      {children}
    </div>
  )
}

優雅處理快速導航

如果導航到新路由的速度很快,使用者可能會看到不必要的載入指示器閃爍。一種改善使用者體驗的方法是添加初始動畫延遲(例如 100ms)並以不可見狀態(例如 opacity: 0)開始動畫,這樣只有在導航耗時較長時才會顯示載入指示器。

app/styles/global.css
.spinner {
  /* ... */
  opacity: 0;
  animation:
    fadeIn 500ms 100ms forwards,
    rotate 1s linear infinite;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes rotate {
  to {
    transform: rotate(360deg);
  }
}
版本變更
v15.3.0新增 useLinkStatus 鉤子