useLinkStatus

El hook useLinkStatus permite rastrear el estado pendiente de un <Link>. Puedes usarlo para mostrar retroalimentación visual en línea al usuario (como spinners o efectos de texto) mientras se completa la navegación a una nueva ruta.

useLinkStatus es útil cuando:

  • El prefetching está deshabilitado o en progreso, lo que significa que la navegación está bloqueada.
  • La ruta de destino es dinámica y no incluye un archivo loading.js que permitiría una navegación instantánea.
'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>
  )
}

Importante:

  • useLinkStatus debe usarse dentro de un componente descendiente de un componente Link
  • El hook es más útil cuando se establece prefetch={false} en el componente Link
  • Si la ruta enlazada ha sido prefetcheada, se omitirá el estado pendiente
  • Al hacer clic en múltiples enlaces rápidamente, solo se muestra el estado pendiente del último enlace
  • Este hook no es compatible con el Pages Router y siempre devolverá { pending: false }

Parámetros

const { pending } = useLinkStatus()

useLinkStatus no recibe parámetros.

Valores devueltos

useLinkStatus devuelve un objeto con una sola propiedad:

PropiedadTipoDescripción
pendingbooleantrue antes de actualizar el historial, false después

Ejemplo

Indicador de carga en línea

Es útil agregar retroalimentación visual que indique que la navegación está ocurriendo en caso de que el usuario haga clic en un enlace antes de que se complete el prefetching.

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

Manejo elegante de navegación rápida

Si la navegación a una nueva ruta es rápida, los usuarios pueden ver un destello innecesario del indicador de carga. Una forma de mejorar la experiencia del usuario y solo mostrar el indicador de carga cuando la navegación tarda en completarse es agregar un retraso inicial en la animación (ej. 100ms) y comenzar la animación como invisible (ej. 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);
  }
}
VersiónCambios
v15.3.0Se introdujo useLinkStatus.