Skip to content
Advertisement

NextJs doesn’t rerun scripts

When I use the <Link> tag in NextJs to navigate between pages it doesn’t rerun my scripts after changing pages. It only runs the scripts after the first page load or when I press reload. When using plain <a> tags instead, it works fine because the page reloads after each navigation. As far as I can tell this happens because the <Link> tag makes it a Single-Page Application and doesn’t refresh the page when navigating between pages.

I would greatly appreciate anyway to have it rerun the scripts when navigating between pages or to have it refresh the page without using just plain <a> tags and losing the Single-Page Application functionality.

This code doesn’t refresh the page

 <Link href="/page1">
   <a>Page 1</a>
 </Link>
 <Link href="/page2">
   <a>Page 2 </a>
 </Link>

This code does refresh the page

 <a href="/page1">Page 1</a>
 <a href="/page2">Page 2 </a>

I load in all my scripts using a scripts component

export default const MyScripts = () => {
    
    return (
        <Script
            strategy="afterInteractive"
            type="module"
            src="/scripts/myScript.js"
            onReady={() => {
                console.log("Ready")
            }}
        /> 
    )
}

One thing I’ve noticed is that the above onReady function fires each time I change pages. Maybe someone knows how to run the myScript.js from the onReady.

Advertisement

Answer

Caution: The hack of using history.pushState will not work reliably, especially when DOM elements need to be fetched using document.querySelector*. Anyway, it’s also better to avoid hacks if you can.

I think the correct and clean way to do this is to use the useEffect React hook (or componentDidMount in class-based components).

This idea was proposed here: samplep182’s comment in: Normal scripts “” not working after page navigation · Issue #4477 · vercel/next.js

Simply move the Javascript code from your script tag into a useEffect block. Remove the script tag and any script file as you no longer need them.

import { useEffect } from 'react';

export default const MyScripts = () => {
  useEffect(() => {
    // Paste the contents of /scripts/myScript.js here (and remove that file)
  }, []);
}

Note that it’s recommended to have an empty array [] as the dependency list, to execute this on page load only.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement