Reputation: 3
I'm trying to load a JavaScript file from a URL in my React application.
I'm using a <script> in the head of HTML of my project. I can see it loaded in the network of the console Chrome, and that's OK.
Now I'm trying to use a function from this file in my React application, with window.nameOfTheFunction, but I cannot access it.
How can I do that?
Upvotes: 0
Views: 449
Reputation: 576
Using the window function is non ideal. How you do it depends on where the .js code is.
If the JavaScript is located on your server then the best way to approach it is to bundle the JavaScript code with a bundler such as Webpack and then use the import function.
If you want to use JavaScript from a remote server then you need to load the code and confirm it's loaded before using it. The reason is that some code may load slower from your source due to its size or network traffic and you don't want your code to break because of those reasons. The following code should help:
function App() {
const status = useScript(
'https://pm28k14qlj.codesandbox.io/test-external-script.js'
);
return (
<div>
<div>
Script status: <b>{status}</b>
</div>
{status === "ready" && (
<div>
Script function call response: <b>{TEST_SCRIPT.start()}</b>
</div>
)}
</div>
);
}
// Hook
function useScript(src) {
// Keep track of script status ("idle", "loading", "ready", "error")
const [status, setStatus] = React.useState(src ? "loading" : "idle");
React.useEffect(
() => {
// Allow falsy src value if waiting on other data needed for
// constructing the script URL passed to this hook.
if (!src) {
setStatus("idle");
return;
}
// Fetch existing script element by src
// It may have been added by another intance of this hook
let script = document.querySelector(`script[src="${src}"]`);
if (!script) {
// Create script
script = document.createElement("script");
script.src = src;
script.async = true;
script.setAttribute("data-status", "loading");
// Add script to document body
document.body.appendChild(script);
// Store status in attribute on script
// This can be read by other instances of this hook
const setAttributeFromEvent = (event) => {
script.setAttribute(
"data-status",
event.type === "load" ? "ready" : "error"
);
};
script.addEventListener("load", setAttributeFromEvent);
script.addEventListener("error", setAttributeFromEvent);
} else {
// Grab existing script status from attribute and set to state.
setStatus(script.getAttribute("data-status"));
}
// Script event handler to update status in state
// Note: Even if the script already exists we still need to add
// event handlers to update the state for *this* hook instance.
const setStateFromEvent = (event) => {
setStatus(event.type === "load" ? "ready" : "error");
};
// Add event listeners
script.addEventListener("load", setStateFromEvent);
script.addEventListener("error", setStateFromEvent);
// Remove event listeners on cleanup
return () => {
if (script) {
script.removeEventListener("load", setStateFromEvent);
script.removeEventListener("error", setStateFromEvent);
}
};
},
[src] // Only re-run effect if script src changes
);
return status;
}
Upvotes: 1