Disable data prefetch (on <Link> hover) for routes using getStaticProps, Next 14.2.5
Answered
Japanese anchovy posted this in #help-forum
Japanese anchovyOP
I have a relatively simple eCommerce application that has a list page for all products, and details pages for each individual product. In
Is there a way to disable the prefetching behavior for these links in Next 14.2.5? I've tried the following:
-
- In next.config.js,
- In next.config.js,
getStaticProps
we hit an endpoint that is rate limited (around 3 requests per second). Next.js seems to be prefetching the data of each of these product details pages when the user hovers over the <Link>
, and this can easily overwhelm the rate limit of the API endpoint. Is there a way to disable the prefetching behavior for these links in Next 14.2.5? I've tried the following:
-
<Link prefetch={false}>...
- In next.config.js,
experimental: { optimisticClientCache: false }
- In next.config.js,
experimental: { disableOptimizedLoading: true }
Answered by joulev
in this case try this
function isModifiedEvent(event: React.MouseEvent): boolean {
const eventTarget = event.currentTarget as HTMLAnchorElement | SVGAElement
const target = eventTarget.getAttribute('target')
return (
(target && target !== '_self') ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey || // triggers resource download
(event.nativeEvent && event.nativeEvent.which === 2)
)
}
function Link({ href }) {
const router = useRouter();
return (
<a
href={href}
onClick={e => {
if (isModifiedEvent(e)) return;
e.preventDefault();
router.push(href);
}}
>
{children}
</a>
);
}
28 Replies
Japanese anchovyOP
We're currently using this scary fix https://github.com/vercel/next.js/discussions/24437#discussioncomment-3752350
getStaticProps should be run at build time though. So in runtime no matter how many times the user tries to visit the page it won’t trigger the rate limited fetch
Japanese anchovyOP
we have disabled the build time compilation step for now, for unrelated reasons
No… don’t serve dev mode to your users
Dev mode is slow and unoptimised. Serve production mode only.
Japanese anchovyOP
We are not using dev mode, but we have returned an empty array for
getStaticPaths
on the product details page componentoh i see what you mean
getStaticProps only sends the request once though, then cached after
or is the problem here due to 3+ different users hovering over 3+ different links at the same time?
Japanese anchovyOP
The unwanted behavior can be triggered by a single user who happens to hover over several links quickly, which is certainly possible
We've worked on mitigating that issue, I'm really more concerned with the eager
prefetch
behavior, specificallyin this case try this
function isModifiedEvent(event: React.MouseEvent): boolean {
const eventTarget = event.currentTarget as HTMLAnchorElement | SVGAElement
const target = eventTarget.getAttribute('target')
return (
(target && target !== '_self') ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey || // triggers resource download
(event.nativeEvent && event.nativeEvent.which === 2)
)
}
function Link({ href }) {
const router = useRouter();
return (
<a
href={href}
onClick={e => {
if (isModifiedEvent(e)) return;
e.preventDefault();
router.push(href);
}}
>
{children}
</a>
);
}
Answer
and use this
Link
instead of next/link
basically a
next/link
clone without prefetchingyou can read the [source code of
next/link
](https://github.com/vercel/next.js/blob/5a2440606cec6a71887fa97b8e617e0e26e2a39e/packages/next/src/client/link.tsx#L206) to port more features to this clone if you wantJapanese anchovyOP
🤔 that's an interesting approach
I really should have read that source at this point
link prefetch is by design, cannot fully turn that off. but can always make a link clone
or you can also make a proxy between that rate limited server and your nextjs app, which is the better solution but requires far more effort and resources
Japanese anchovyOP
it looks like that is the case in the "pages" router, which we are still using for these. I'll have to see how much work it would be to use the "app" router for this part of the application, so that
prefetch={false}
would work as I expectedit will be quite a bit of work, depending on the scale of your app. unless you have lots of time to spare, i wouldn't recommend it just yet
Japanese anchovyOP
I'll consider it—I think I'd only need to move a single component over... though the server components stuff might cause me a bit of trouble. The hack we're currently using to prevent prefetch is working fine, but it does prevent all prefetching, which is not really the goal
the thing is, if you have page A in the pages router, and page B in the app router, navigating from A to B will be a full page refresh, basically the <a> link
so it doesn't help with anything, because <a> link by itself can already be used here without you having to change router
Japanese anchovyOP
Ah, that's a showstopper really...
they are two different react roots so require a browser refresh. client navigation is not possible between react roots
Japanese anchovyOP
Mmmm... what would really complicate things, moving the entire app over would be an endeavor for a couple reasons
I can rely on the hacks for now, but it's nice to know that migrating over to the app router will fix a couple extra things along the way