useLinkStatus Hook 允许您跟踪 <Link> 的挂起状态。您可以使用它来实现微妙的内联反馈,例如在点击链接时显示微光效果,直到导航完成。优先使用 loading.js 进行路由级回退,以及预取以实现即时过渡。
useLinkStatus 在以下情况下很有用:
loading.js 文件,因此无法实现即时导航。'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>
)
}'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>
)
}须知:
useLinkStatus必须在<Link>组件的后代组件中使用- 当
<Link>组件上设置了prefetch={false}时,这个 Hook 最有用- 如果链接的路由已经被预取,则会跳过挂起状态
- 当快速连续点击多个链接时,只会显示最后一个链接的挂起状态
- 此 Hook 在 Pages Router 中不受支持,并且总是返回
{ pending: false }- 内联指示器很容易导致布局偏移。建议使用固定大小、始终渲染的提示元素并切换其不透明度,或使用动画。
useLinkStatus在添加内联反馈之前,请考虑以下情况:
loading.js 文件,可实现路由级回退的即时过渡。导航通常很快。当您发现慢速过渡时,可以将 useLinkStatus 作为快速修补方案,然后通过预取或 loading.js 回退来迭代解决根本原因。
const { pending } = useLinkStatus()useLinkStatus 不接受任何参数。
useLinkStatus 返回一个包含以下单个属性的对象:
| 属性 | 类型 | 描述 |
|---|---|---|
| pending | boolean | 在历史记录更新前为 true,更新后为 false |
添加一个微妙的、固定大小的提示,它不会影响布局,以在预取未完成时确认点击。
'use client'
import { useLinkStatus } from 'next/link'
export default function LoadingIndicator() {
const { pending } = useLinkStatus()
return (
<span aria-hidden className={`link-hint ${pending ? 'is-pending' : ''}`} />
)
}'use client'
import { useLinkStatus } from 'next/link'
export default function LoadingIndicator() {
const { pending } = useLinkStatus()
return (
<span aria-hidden className={`link-hint ${pending ? 'is-pending' : ''}`} />
)
}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>
)
}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 }) {
return (
<div>
<Menubar />
{children}
</div>
)
}如果导航到新路由的速度很快,用户可能会看到不必要的提示闪烁。一种改善用户体验并仅在导航需要时间完成时才显示提示的方法是添加一个初始动画延迟(例如 100ms),并以不可见状态(例如 opacity: 0)开始动画。
.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.0 | useLinkStatus 引入。 |