skip to Main Content

I want to add some external scripts to my ReactJS/TS app and I would like to add these scripts not into index.html but with another component.

if (root) {
  createRoot(root).render(
    <>
      <Scripts />
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<PageWrapper />}>
            <Route index element={<UserEdit />} />
            <Route path="user/edit" element={<UserEdit />} />
            <Route path="user/:id" element={<UserPage />} />
            <Route path="*" element={<NoPage />} />
          </Route>
        </Routes>
      </BrowserRouter>
    </>
  )
}

this is how I would like code to look. Scripts component looks like this:

const Scripts = () => {
    const scripts: Scripts = ["frontend/js_clean/check.js","frontend/js_clean/user.js"...]
    return ({scripts.map(script => <script key={script} type="text/javascript" src={`${process.env.ASSETS_CDN}/${script}`}></script>)})
}

But the problem is that components which go after Scripts component using variables and functions from external scripts and when I try to start app it gives me an error like:

TypeError: window.isJsonString is not a function

window.isJsonString is declared into frontend/js_clean/user.js script which I try to include into Scripts component. So I am wondering if there is another way to add external scripts to the project without hardcoding it into index.html.

Thanks in advance!

2

Answers


  1. React is all about transforming state (in broad sense) into UI. So, if you are loading something else, you must express it in terms of state.

    For your particular task, set a state variable that will indicate if scripts are loaded or not. It will have three possible values: "not loaded", "loaded", "error". Attach onLoad and onError handlers you your script elements and change this state accordingly.

    Login or Signup to reply.
  2. What you are doing will not work, because you are adding <script> tags to work with JSX. There is no React doc that mentions they handle these tags.

    Infact, we can be sure that it does not download the scripts, let alone execute them. Here is a Demo, where I have added a single script tag in JSX and it did not work.

    What we have to realise is that what we return from inside React function component is not HTML, but JSX. That JSX is converted to DOM elements by React, and if we include a <script> tag it will only work if React handles it. That does not happen right now.

    Infact, it is a feature that will soon be introduced in react. Right now in canary.


    Until then, if you don’t want to include your scripts in index.html, you have two options:

    1. Initialize them from index.js, or
    2. Lazy load based on the component that uses them.

    Both approaches require you to do some DOM manipulation. What you want to do is create a script element and update its attributes and append it to the DOM.

    There is a hook already for that. useScript It lazy loads the script when the component using it is invoked. But the DOM manipulations in the source code is what you also can use to add script tags to the HTML.


    Here is a super minified version which handles multiple scripts:

    const useScriptsAfterMount = () => {
    useEffect(() => {
    let scriptsList = ['https://maps.googleapis.com/maps/api/js?key=&'];
    scriptsList.forEach((scriptSrc) => {
      const script = document.createElement('script');
      script.src = scriptSrc;
      document.body.appendChild(script);
    });
    }, []);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search