useLinkStatus

useLinkStatus 钩子用于追踪 <Link> 组件的 pending 状态。您可以使用它在导航到新路由完成时向用户显示内联视觉反馈(如加载旋转图标或文字闪烁效果)。

useLinkStatus 在以下场景中特别有用:

'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>
  )
}

优雅处理快速导航

如果导航到新路由的速度很快,用户可能会看到不必要的加载指示器闪烁。一种改善用户体验的方法是添加初始动画延迟(例如 100 毫秒)并以不可见状态(例如 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 钩子。