-
Notifications
You must be signed in to change notification settings - Fork 68.3k
Expand file tree
/
Copy pathprefetch.ts
More file actions
46 lines (42 loc) · 2.02 KB
/
Copy pathprefetch.ts
File metadata and controls
46 lines (42 loc) · 2.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { useCallback } from 'react'
import type { useRouter } from 'next/router'
type Router = ReturnType<typeof useRouter>
// Session-lived de-dupe set. Module scope (not a per-component useRef) so it
// survives the sidebar's per-navigation remount — otherwise the cache would
// reset every nav and "de-duped per href" would only hold within a single page.
// Bounded by the number of distinct internal hrefs the user hovers/focuses.
const prefetchedHrefs = new Set<string>()
// Brand NavList/Breadcrumbs items render plain <a>s navigated via router.push,
// so Next.js doesn't prefetch their destinations the way next/link would. This
// hook warms a route on hover/focus.
//
// Scope of the benefit here is small on purpose: every article is a
// getServerSideProps route, and router.prefetch only fetches the JS bundle for
// those (not the getServerSideProps data), while page data is already served fast
// from the Fastly edge. All articles also share one [...restPage] bundle, so after
// the first navigation there's usually nothing left to fetch. It still helps the
// first cold visit, and would fetch data too if a route ever moves to
// getStaticProps. router.prefetch is production-only (no prefetch in dev); we
// de-dupe per href so re-entering a link doesn't re-issue.
export function usePrefetchOnInteraction() {
const prefetch = useCallback(async (router: Router, href: string) => {
if (
process.env.NODE_ENV !== 'production' ||
!href.startsWith('/') ||
prefetchedHrefs.has(href)
) {
return
}
prefetchedHrefs.add(href)
try {
// hrefs already include the locale prefix (e.g. /en/...), so disable Next.js
// locale handling to match the router.push calls at the click sites.
await router.prefetch(href, undefined, { locale: false })
} catch {
// A transient chunk/network failure shouldn't permanently suppress retries;
// un-mark so a later hover/focus can try again (mirrors next/link).
prefetchedHrefs.delete(href)
}
}, [])
return prefetch
}