コンテンツにスキップ

useLinkStatus

useLinkStatus フックを使用すると、<Link> の **pending** 状態を追跡できます。これを、ナビゲーションが完了するまでの間、クリックされたリンクにシェイマー効果を適用するなど、微妙なインラインフィードバックに使用します。loading.js を使用したルートレベルのフォールバックや、プリフェッチによる即時遷移を優先してください。

useLinkStatus が役立つのは

  • プリフェッチが無効になっているか、進行中であり、ナビゲーションがブロックされている場合。
  • 宛先ルートが動的であり、**かつ**、即時ナビゲーションを可能にする loading.js ファイルを含んでいない場合。
app/hint.tsx
'use client'
 
import Link from 'next/link'
import { useLinkStatus } from 'next/link'
 
function Hint() {
  const { pending } = useLinkStatus()
  return (
    <span aria-hidden className={`link-hint ${pending ? 'is-pending' : ''}`} />
  )
}
 
export default function Header() {
  return (
    <header>
      <Link href="/dashboard" prefetch={false}>
        <span className="label">Dashboard</span> <Hint />
      </Link>
    </header>
  )
}

知っておくと良いこと:

  • useLinkStatusLink コンポーネントのdescendant コンポーネント内で使用する必要があります
  • このフックは Link コンポーネントで prefetch={false} が設定されている場合に最も役立ちます。
  • リンク先のルートがプリフェッチされている場合、pending 状態はスキップされます。
  • 複数のリンクを短時間にクリックした場合、最後のリンクの pending 状態のみが表示されます。
  • このフックは Pages Router ではサポートされておらず、常に { pending: false } を返します。
  • インラインインジケータはレイアウトシフトを容易に引き起こす可能性があります。固定サイズの常にレンダリングされるヒント要素を使用して透明度を切り替えるか、アニメーションを使用してください。

useLinkStatus は不要かもしれません

インラインフィードバックを追加する前に、以下を検討してください。

  • 宛先は静的で、本番環境でプリフェッチされているため、pending フェーズはスキップされる可能性があります。
  • ルートに loading.js ファイルがあり、ルートレベルのフォールバックによる即時遷移が可能になります。

ナビゲーションは通常高速です。useLinkStatus は、遅い遷移を特定した際の迅速な修正として使用し、その後、プリフェッチまたは loading.js フォールバックで根本原因を修正するようにイテレーションしてください。

Parameters

const { pending } = useLinkStatus()

useLinkStatus はパラメータを取りません。

戻り値

useLinkStatus は単一のプロパティを持つオブジェクトを返します。

プロパティタイプ説明
pendingboolean履歴の更新前は true、更新後は false

プリフェッチが完了していない場合にクリックを確認するため、レイアウトに影響しない、微妙な固定サイズのヒントを追加します。

app/components/loading-indicator.tsx
'use client'
 
import { useLinkStatus } from 'next/link'
 
export default function LoadingIndicator() {
  const { pending } = useLinkStatus()
  return (
    <span aria-hidden className={`link-hint ${pending ? 'is-pending' : ''}`} />
  )
}
app/shop/layout.tsx
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}>
          <span className="label">{link.label}</span> <LoadingIndicator />
        </Link>
      ))}
    </div>
  )
}
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div>
      <Menubar />
      {children}
    </div>
  )
}

高速なナビゲーションをスムーズに処理する

新しいルートへのナビゲーションが速い場合、ユーザーはヒントの不要なフラッシュを目にする可能性があります。ナビゲーションの完了に時間がかかる場合にのみヒントを表示するようにユーザーエクスペリエンスを改善する1つの方法は、初期アニメーション遅延 (例: 100ms) を追加し、アニメーションを不可視 (例: opacity: 0) で開始することです。

app/styles/global.css
.link-hint {
  display: inline-block;
  width: 0.6em;
  height: 0.6em;
  margin-left: 0.25rem;
  border-radius: 9999px;
  background: currentColor;
  opacity: 0;
  visibility: hidden; /* reserve space without showing the hint */
}
 
.link-hint.is-pending {
  /* Animation 1: fade in after 100ms and keep final opacity */
  /* Animation 2: subtle pulsing while pending */
  visibility: visible;
  animation-name: fadeIn, pulse;
  animation-duration: 200ms, 1s;
  /* Appear only if navigation actually takes time */
  animation-delay: 100ms, 100ms;
  animation-timing-function: ease, ease-in-out;
  animation-iteration-count: 1, infinite;
  animation-fill-mode: forwards, none;
}
 
@keyframes fadeIn {
  to {
    opacity: 0.35;
  }
}
@keyframes pulse {
  50% {
    opacity: 0.15;
  }
}

バージョン履歴

バージョン変更履歴
v15.3.0useLinkStatus が導入されました。