Next.js Discord

Discord Forum

Disable data prefetch (on <Link> hover) for routes using getStaticProps, Next 14.2.5

Answered
Japanese anchovy posted this in #help-forum
Open in Discord
Avatar
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 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>
  );
}
View full answer

28 Replies

Avatar
Japanese anchovyOP
Avatar
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
Avatar
Japanese anchovyOP
we have disabled the build time compilation step for now, for unrelated reasons
Avatar
No… don’t serve dev mode to your users
Dev mode is slow and unoptimised. Serve production mode only.
Avatar
Japanese anchovyOP
We are not using dev mode, but we have returned an empty array for getStaticPaths on the product details page component
Avatar
oh 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?
Avatar
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, specifically
Avatar
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>
  );
}
Answer
Avatar
and use this Link instead of next/link
basically a next/link clone without prefetching
you 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 want
Avatar
Japanese anchovyOP
🤔 that's an interesting approach
I really should have read that source at this point
Avatar
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
Avatar
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 expected
Image
Avatar
it 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
Avatar
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
Avatar
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
Avatar
Japanese anchovyOP
Ah, that's a showstopper really...
Avatar
they are two different react roots so require a browser refresh. client navigation is not possible between react roots
Avatar
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