主题
useLinkStatus
useLinkStatus 钩子允许你跟踪 <Link> 的待处理状态。用于提供微妙的内联反馈,例如在导航完成时,点击链接上方的闪烁效果。建议在路由级别使用 loading.js 作为回退,并使用预取来实现即时过渡。
¥The useLinkStatus hook lets you track the pending state of a <Link>. Use it for subtle, inline feedback, for example a shimmer effect over the clicked link, while navigation completes. Prefer route-level fallbacks with loading.js, and prefetching for instant transitions.
useLinkStatus 在以下情况下有用:
¥useLinkStatus is useful when:
预请求 已禁用或正在运行,这意味着导航被阻止。
¥Prefetching is disabled or in progress meaning navigation is blocked.
目标路由是动态的,不包含允许即时导航的
loading.js文件。¥The destination route is dynamic and doesn't include a
loading.jsfile that would allow an instant navigation.
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>
)
}需要了解:
¥Good to know:
useLinkStatus必须在Link组件的后代组件中使用¥
useLinkStatusmust be used within a descendant component of aLinkcomponent当
prefetch={false}设置在Link组件上时,此钩子最有用。¥The hook is most useful when
prefetch={false}is set on theLinkcomponent如果链接的路由已预取,则将跳过待处理状态。
¥If the linked route has been prefetched, the pending state will be skipped
快速连续点击多个链接时,仅显示最后一个链接的待处理状态。
¥When clicking multiple links in quick succession, only the last link's pending state is shown
此钩子在 Pages Router 中不受支持,并且始终返回
{ pending: false }。¥This hook is not supported in the Pages Router and always returns
{ pending: false }内联指示器很容易导致布局偏移。建议使用固定大小、始终渲染的提示元素,并切换其透明度,或者使用动画。
¥Inline indicators can easily introduce layout shifts. Prefer a fixed-size, always-rendered hint element and toggle its opacity, or use an animation.
你可能不需要 useLinkStatus
¥You might not need useLinkStatus
添加内联反馈之前,请考虑以下事项:
¥Before adding inline feedback, consider if:
目标位置是静态的,并且在生产环境中会进行预取,因此可以跳过等待阶段。
¥The destination is static and prefetched in production, so the pending phase may be skipped.
路由包含一个
loading.js文件,从而实现路由级别的回退并进行即时转换。¥The route has a
loading.jsfile, enabling instant transitions with a route-level fallback.
导航通常很快。当发现转换缓慢时,使用 useLinkStatus 作为快速补丁,然后迭代修复根本原因,例如使用预取或 loading.js 回退方案。
¥Navigation is typically fast. Use useLinkStatus as a quick patch when you identify a slow transition, then iterate to fix the root cause with prefetching or a loading.js fallback.
参数
¥Parameters
tsx
const { pending } = useLinkStatus()useLinkStatus 不带任何参数。
¥useLinkStatus does not take any parameters.
返回
¥Returns
useLinkStatus 返回一个具有单个属性的对象:
¥useLinkStatus returns an object with a single property:
| 属性 | 类型 | 描述 |
|---|---|---|
| pending | boolean | true 在历史记录更新之前,false 在历史记录更新之后 |
示例
¥Example
内联链接提示
¥Inline link hint
添加一个不影响布局的细微固定大小提示,用于在预取尚未完成时确认点击操作。
¥Add a subtle, fixed-size hint that doesn’t affect layout to confirm a click when prefetching hasn’t completed.
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' : ''}`} />
)
}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>
)
}优雅地处理快速导航
¥Gracefully handling fast navigation
如果跳转到新路由的速度很快,用户可能会看到不必要的提示闪烁。一种改善用户体验的方法,即仅在导航耗时较长时才显示提示,是添加初始动画延迟(例如 100 毫秒),并将动画设置为不可见状态(例如 opacity: 0)。
¥If the navigation to a new route is fast, users may see an unnecessary flash of the hint. One way to improve the user experience and only show the hint when the navigation takes time to complete is to add an initial animation delay (e.g. 100ms) and start the animation as invisible (e.g. opacity: 0).
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;
}
}版本历史
¥Version History
| 版本 | 更改 |
|---|---|
v15.3.0 | useLinkStatus 已引入。 |