New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
next/script onLoad run once per cache Key (id, src) #30962
Comments
I just need same feature (fire onLoad every time, when script is added to attach some event listener). Any news here? Meanwhile I use hook: import { useEffect, useState } from 'react';
type Callback = () => void;
interface ScriptAttributes {
id: string;
src: string;
async: 'async';
defer: 'defer';
}
function setAttributes<T>(el: Element, attributes: T): void {
Object.keys(attributes).forEach((key: string) => {
el.setAttribute(key, attributes[key]);
});
}
function addScript(scriptUrl: string, elName: string, callback: Callback | undefined): void {
const elScriptId = `${elName}-script`;
const elScriptPresent: HTMLElement | null = document.getElementById(elScriptId);
// Avoid multiple inserting of script element.
if (elScriptPresent) {
if (callback) {
callback();
}
return;
}
const elScript: HTMLScriptElement = document.createElement('script');
if (callback) {
elScript.onload = () => callback();
}
setAttributes<ScriptAttributes>(elScript, {
id: elScriptId,
src: scriptUrl,
async: 'async',
defer: 'defer',
});
document.body.appendChild(elScript);
}
function useScript(name: string, src: string): boolean {
const [loaded, setLoaded] = useState<boolean>(false);
const callback: Callback = () => setLoaded(true);
useEffect(() => {
addScript(src, name, callback);
});
return loaded;
}
export default useScript; And usage: // inside component where is script loaded
const loaded = useScript();
useEffect(() => {
if (elementRef.current && loaded) {
elementRef.current.addEventListener('someevent', (e) => ...);
}
}, [loaded]); |
Any words from Next. We also use a hook based on this one and it's working perfectly. |
@housseindjirdeh can I help doing something about this issue? |
I think it's technically correct to call It seems safer to add a new event handler that fires once the script is ready. So once it basically fire with the For our use case specifically we were loading a 3rd party library. So we started out with a "pending" state and flipped that to "resolved" in There are still some race conditions we might be missing though. |
I can agree with you that In my experiences I didn't find a case where I need an |
Sure. But that's a documentation issue i.e. use |
Sorry for the delay here again folks. I actually misread the issue the first time around and thought the problem was that I actually agree with @eps1lon here. If a single script is loaded once, then I wouldn't expect @bordeo One more question: Why are you using more than one Script with the same |
While I don't disagree that firing What about adding an |
Thank you @housseindjirdeh for your reply. But the problem manifests itself even when one I don't think all this is correct behavior. Maybe firing an onReady event could be the right way to solve this issue. |
Thanks for the details @zacharyliu and @bordeo. I think I fully understand the concern now. I agree that it would probably make more sense to have a separate prop for this (e.g. useEffect(() => {
if (onReady) {
onReady()
}
}, [onReady]) There's no guarantee that this would run before |
I think it would need to run at the same time as As a more concrete example, the Google Maps JS SDK requires running |
@zacharyliu explains very well. It would be better if |
Thanks for brainstorming with me folks, I appreciate it :) PR #38849 should solve for this by introducing |
Can't wait for it. :) |
Closes: #30962 This PR adds a new `onReady` prop to `next/script` to handle shortcomings of the current `onLoad` prop. Some third-party providers and widgets require initialization code to run after the script's `load` event and every time the component is mounted. The `onReady` should solve that use case. For more details, refer to the discussion in #30962. CC @janicklas-ralph ## Bug - [X] Related issues linked using `fixes #number` - [X] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
What version of Next.js are you using?
12.0.2
What version of Node.js are you using?
14.18.1
What browser are you using?
Chrome
What operating system are you using?
macOS
How are you deploying your application?
codesandbox
Describe the Bug
When using more than one
Script
with sameid
orsrc
, only first script that complete load trigger theonLoad
prop.Same problem happens using one
Script
but after unmount and remount, for example when navigating throughout client-side router theonLoad
will not be called.@giorgiabosello
Expected Behavior
Script
component should load once the src script but runonLoad
on component did mount and script is loaded.To Reproduce
https://codesandbox.io/s/nextjs-script-onload-ltm95
The text was updated successfully, but these errors were encountered: