Script tag for Next.js reloading functionality

I have been facing a challenge while trying to integrate third-party commenting scripts like (disqus, remark42, hyvor) into my next.js application. The issue I encountered is that the script only loads on the initial page load. Subsequently, I need to refresh the page for the embedded third-party script to become visible. This poses a problem as it goes against the nature of react/next.js since next.js does not reload when navigating to another page using the Link component. Therefore, I am seeking a solution to selectively reload the Script component itself in order to ensure that my commenting widget appears consistently on every article page throughout the website.

code:

export const getStaticPaths: GetStaticPaths = async () => {
  const data = await getArticles();

  const paths = data.map((article) => ({
    params: {
      slug: article?.slug,
    },
  }));

  return {
    paths,
    fallback: true,
  };
};

export const getStaticProps = async ({
  params,
}: GetStaticPropsContext<{ slug: string }>) => {
  const article = await getArticleByProp("slug", params!.slug);

  return {
    props: {
      article: article[0],
    },
    notFound: article.length === 0,
    revalidate: 60,
  };
};

const ArticlePage = ({
  article,
}: InferGetStaticPropsType<typeof getStaticProps>) => {
  const router = useRouter();
  const formattedDate = useFormattedDate(
    article?.createdAt ? new Date(article.createdAt) : new Date(),
    "distance"
  );

  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  return (
    <Container>
      <SEOHeader
        title={article?.title}
        author={article?.author}
        description={article?.excerpt}
        ogImage={article?.featuredImage}
        canonical={article?.slug}
      />
      <Wrapper>
        <ArticleWrapper>
          <ArticleHeader>
            <small className="category">{article?.category}</small>
            <h1 className="title">{article?.title}</h1>
            <p className="contributor">
              <span>
                By <strong> {article?.author}</strong> <br />
              </span>
            </p>
            <div className="date">
              <Clock size={18} />{" "}
              <span>{article?.createdAt ? formattedDate : "N/A"}</span>
            </div>
            <button className="share">
              <Share size={24} />
            </button>
          </ArticleHeader>
          <ArticleBody>
            {!!article?.featuredImage && (
              <Featured>
                <Image
                  src={article.featuredImage}
                  layout="responsive"
                  width={1920}
                  height={1080}
                  alt="Featured article image"
                />
              </Featured>
            )}
            <ArticleExcerpt>{article?.excerpt}</ArticleExcerpt>
            <ArticleMdx>{article?.body}</ArticleMdx>
          </ArticleBody>
          <div id="remark42">{""}</div>

          {/* Additional scripting commented out */}

          <Script id="custom-script-example">{`
          const custom_config = {
            host: 'https://example.com',
            site_id: 'custom-site',
          };
          window.custom_config = custom_config;
          !function(e,n){for(var o=0;o<e.length;o++){var s=n.createElement("script"),c=".js",a=n.head||n.body;"noModule"in s?(s.type="module",c=".mjs"):s.async=!0,s.defer=!0,s.src=custom_config.host+"/web/"+e[o]+c,a.appendChild(s)}}(custom_config.components||["embed"],document);
          `}</Script>
          
        </ArticleWrapper>
        <Recommended>
          <h2>Recommended</h2>
          <ArticleCard card={article} variant="slim" />
          <ArticleCard card={article} variant="slim" />
          <ArticleCard card={article} variant="slim" />
          <ArticleCard card={article} variant="slim" />
        </Recommended>
      </Wrapper>
    </Container>
  );
};

export default ArticlePage;

Answer №1

Perhaps this solution can assist with related issues:

The newer onReady prop provided by next/script is particularly handy for managing third-party maps, widgets, and more.

You have the ability to run code after the script has finished loading initially, as well as after each subsequent component remount by utilizing the onReady property.

Here's a snippet from the documentation showcasing how it works:

      <Script
        id="google-maps"
        src="https://maps.googleapis.com/maps/api/js"
        onReady={() => {
          new google.maps.Map(mapRef.current, {
            center: { lat: -34.397, lng: 150.644 },
            zoom: 8,
          })
        }}
      />

Answer №2

The script component from 'next/script' functions in a similar manner to what was discussed in the question. It will load the script when you first visit or refresh the page, and then cache it so that it doesn't reload when navigating between pages.

In order to meet the requirement of reloading the script while navigating back and forth, some custom adjustments using Vanilla JS and contextual ref need to be made.

Refer to the code below and make the necessary changes to your code as per the requirements -

export default function LoyaltyRewards(): JSX.Element | null {
    const socialAnnexRef = useRef<HTMLDivElement>(null)

    const script = `
        // Insert any script you want here
        <script id="social-annex">
            var siteID = '${siteId}';
            var sa_emailid = '${sAEmailId}';
            var token = '${token}';
            var sa_uni = sa_uni || []; sa_uni.push(['sa_pg', '5']);
            (function () {
                function sa_async_load () {
                    var sa = document.createElement('script');
                    sa.type = 'text/javascript';
                    sa.async = true; sa.src="https://cdn.socialannexuat.com/partner/${siteId}/universal.js";
                    var sax = document.getElementsByTagName('script')[0]; sax.parentNode.insertBefore(sa, sax);
                }
                sa_async_load();
            })();
        </script>
    `

    useEffect(() => {
        /* Clear out the loaded script on component un-mount */
        return () => {
            document.getElementById('social-annex')?.remove()
            document.getElementById('sa_load_loader')?.remove()
            document.getElementById('socialannex-s15dasboard')?.remove()
            document.getElementById('social-annex-universal')?.remove()
        }

        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    useEffect(() => {
        if (siteId) {
            const range = document.createRange()
            const documentFragment = range.createContextualFragment(script)
            socialAnnexRef.current?.appendChild(documentFragment)
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [siteId])

    return (
        <div className="mt-8" ref={socialAnnexRef}>
            <div id="socialannex_dashboard" />
        </div>
    )
}

This should provide assistance for you or others in the future. Thank you!

Happy Coding :-)

Answer №3

next/script is designed to execute only once, which is why many developers prefer it over native script. However, there are scenarios where this behavior may not be suitable.

In a similar situation I encountered, I opted to steer clear of next/script altogether as it lacks support for reloading. Instead, I chose to inject the script using vanilla JavaScript within a useEffect hook for better control.

function MyComponent() {
  useEffect(() => {
    const scriptTag = document.createElement('script')
    var code = `/*** insert your JavaScript code here ***/`
    scriptTag.appendChild(document.createTextNode(code)) // or use scriptTag.src = 'my-js-file.js' if you wish to link an external file
    document.body.appendChild(scriptTag)
  }, [yourDependency]) // consider using a variable related to navigation to trigger the script on page changes

  return <></>
}

export default MyComponent

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Dependencies in Scala.js for CSS styling

I am currently having an issue implementing Scala.js with the bootstrap library. Including the js file was a simple and straightforward process: jsDependencies +="org.webjars" % "bootstrap" % "3.3.7-1" / "bootstrap.js" minified "bootstrap.min.js" However ...

Updating the state of an object within a mapping function

I've been struggling with this issue for two days now. Despite my efforts to find a solution online, I am still stuck and starting to believe that I might be missing something. The main functionality of the app is to click a button and watch an apple ...

Adjust the camera in threejs to be positioned inside a different object

My goal is to adjust the camera controlled by trackballControl to match the position of an object. Currently, it's functioning correctly but as demonstrated in this example, each time the camera changes its position, the z value also changes, which i ...

Failed to retrieve information using a custom header in the HTTP request

My AngularJS code works well without the header option. $http.get(env.apiURL()+'/banks', { headers: { 'Authorization': 'Bearer '+localStorageService.get('access_token') } }) Here is the request: OP ...

TinyMCE generates HTML code with embedded tags

Hey there, I'm currently facing an issue with TinyMCE that I just can't seem to solve. I've browsed through some related posts but haven't found a solution that works for me... For example: When I input something in my back office, ...

What is the optimal event to trigger a function when there is any modification in a text area using Javascript?

I need a function to trigger every time there is any modification in my textarea, such as characters being typed, deleted, cut, pasted, etc. Currently, I am using: onkeyup || onmousemove = function(); It appears that only onmousemove is being triggered. ...

Implementing a click event on header elements within a full calendar component in a React application

I'm currently integrating full calendar into my project. I need to implement click events on the header buttons such as prev, next, today, and others. This is how I've set up full calendar with the specified header buttons: <FullCalendar d ...

Setting up a new package through JPSM installation

I utilize jspm in my web application. My goal is to install the npm:angular2 package without needing to set it up in the config.js file. Instead of loading the angular2 module via jspm, I manually added the angular2 library like this: <script src="jspm ...

Click on a Marker to automatically zoom to its location using Leaflet mapping technology

I have successfully implemented a feature to display markers on the map from a geojson file. Currently, when I hover over a marker, I can see its properties in a popup. However, I now want to enhance this functionality so that when a user clicks on a mar ...

when passing a JavaScript symbol in Django's JSON objects, it does not display properly

When working with Django (2.2), my goal is to send a JSON response in this format: return JsonResponse(data, safe=False) Within the data object, there is a value that looks like this: "unit": "\u33A5" (cubic meters). However, ...

Secure your desktop application with OAuth by enabling HTTPS on localhost

I am currently in the process of developing a desktop application that integrates with Spotify's oauth api using the implicit grant flow as outlined here: My plan is to incorporate an "Authenticate" button, which when clicked will open the user' ...

Exploring the Fundamentals of XSS

Currently, my technology stack consists of Symfony2, Twig, and Doctrine. When it comes to securing my website, I am particularly concerned about preventing XSS attacks. However, despite taking precautions, I'm not sure what more I can do. Persisten ...

Creating a render function that includes the img.src parameter requires careful thought and consideration

I am currently working on a dilemma where I need to dynamically adjust the height and width of an image in my render() function every time there is a state change. Here is the code snippet: render() { const imageURL = photos[this.state.currentImage]. ...

The candy stripes on a loading bar zebra assist in creating a unique and

I'm in the process of creating my portfolio and I'd like to incorporate unique animated loading bars, such as vertical or horizontal candy stripes, to showcase my coding skills. Can anyone suggest a specific programming language or tool that woul ...

The unique font I have set up is not displaying correctly on Safari or iOS devices, however, it is functioning properly on Chrome and Firefox when using

This is my first time seeking help on stackoverflow. I have been struggling to understand why the font on my website doesn't display correctly in Safari or any browser on IOS devices, even though it appears fine on Chrome, Firefox, and other browsers. ...

The Date Picker pops up automatically upon opening the page but this feature is only available on IE10

There seems to be an issue with the date picker opening automatically on IE10, while it works fine in Firefox where it only appears when you click on the associated text box. Does anyone have insight into why this might be happening specifically in IE10? ...

I encountered an issue in ReactJS where I received a TypeError stating that props.history.listen is not a function

Why is this showing up? I'm using ReactJS and can't figure out what's going wrong. Here is my history.js: import { createBrowserHistory } from 'history' export default createBrowserHistory In my App.js: import React from 'r ...

Retrieving data in Next.js

Exploring various techniques to retrieve information from APIs in next.js. Options include getServerSideProps, getStaticPaths, getStaticProps, Incremental Static Regeneration, and client-side rendering. If I need to send requests to the backend when a s ...

What is the method for exiting full screen mode in NextJS?

'use client' const App = () => { const [isFScreen, setIsFScreen] = useState(false) useEffect(() => { const down = (e: KeyboardEvent) => { if (e.key === "Escape"){ setIsFScreen(false) } } docu ...

Is it possible to attach a mouse click event to styled text?

Is there a way to specify a mouse click event for an element with a decoration applied to the text, matched with regex? The option to specify a hoverMessage is available, but I would like to find a way to execute a function based on which decorated text ...