nextjs script doesn't work after router has changed

My external scripts stop to work after the router changes (**When the user click on any link**)

inside _app.js

  import Script from "next/script";

        <Script
          async
          type="text/javascript"
          src="//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js"
        />
  

What it look like on first render
enter image description here

What it look like after router changes

2

What i tried so far

Put it inside the Head tag - this makes it not work at all.

Put the scripts inside _document, this makes the same error.

Upvotes: 4

Views: 3619

Answers (3)

Fardin Ahsan
Fardin Ahsan

Reputation: 91

Add the bellow script on your main layout.

Import useEffect and useRouter

import { useEffect } from "react";
import { useRouter } from "next/router";

Assign file path to scripts object.

let scriptRefArr = []

  const { route } = useRouter()

  useEffect(() => {
    if (route) {
      const scripts = ['/assets/libs/tiny-slider/min/tiny-slider.js', '/assets/libs/tobii/js/tobii.min.js', '/assets/libs/feather-icons/feather.min.js', '/assets/js/plugins.init.js', '/assets/js/app.js'];

      for (let item of scripts) {
        loadScript(item);
      }
    }

    return () => {
      if (scriptRefArr.length > 0) {
        removeScript()
      }

    }

  }, [route]);

  const loadScript = (src) => {
    const script = document.createElement('script');
    script.src = src;
    script.async = true;
    if (!scriptRefArr.find(item => item.url === src)) {
      document.body.appendChild(script);
      scriptRefArr.push({ url: src, script })
    }
  }

  const removeScript = () => {
    scriptRefArr.forEach(item => {
      if (document.body.contains(item.script)) {
        document.body.removeChild(item.script);
      }
    })

  }

Upvotes: 3

Ilir
Ilir

Reputation: 656

After you loaded the script in your _app.js, create a reusable component like this:

import React from 'react';

const TrustpilotWidget = ({ templateId, theme }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {

if (window.Trustpilot) {
  window.Trustpilot.loadFromElement(ref.current, true);
}
  }, []);

  return (
<div
  ref={ref} 
 className="trustpilot-widget"
 data-template-id={templateId}
 data-theme={theme ? theme : "light"}
>
  <a href="https://www.trustpilot.com/review/example.com" target="_blank" rel="noopener"> Trustpilot
  </a>
</div>
  );
};
export default TrustBox;

And then use it in your app wherever you like, like this:

 <TrustpilotWidget
    templateId='your id'
    theme='light'
  />

Upvotes: 0

Adin Ehnsi&#246;
Adin Ehnsi&#246;

Reputation: 1

Add a unique parameter in the src of the external script. And that way it will be added even when using next router.

** Causes issue with script being injected several times :( Problem still unsolved

<Script
  src={`https://somethirdpartyscript.com/service/js?cacheControl=${new Date().getTime()}`}
/>

Upvotes: -1

Related Questions