Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Fixes #39993. Before the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, skip `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` even if it might not fully load yet - Because of React's strict mode, `useEffect` for `onReady` executes again - Since the script's cacheKey is in `LoadCache`, `onReady` is called (even when the script is not loaded yet) - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is called again After the PR: - `next/script` component mount, `useEffect` for `onReady` executes - The script's cacheKey is not added to `LoadCache`, `useEffect` skips `onReady` - The second `useEffect` for `loadScript` executes - The script's cacheKey is added to `LoadCache` only if it is an inline script - Because of React's strict mode, `useEffect` for `onReady` executes again - The script is not yet loaded, its cacheKey is not in `LoadCache`, `useEffect` skips `onReady` again - After the script is actually loaded, inside the `script.onload` event handler the `onReady` is finally called In short, the PR resolves a race condition that only occurs under React strict mode (and makes the `next/script` component more concurrent rendering resilient). ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md`
- Loading branch information
Showing
5 changed files
with
104 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Script from 'next/script' | ||
import Link from 'next/link' | ||
|
||
if (typeof window !== 'undefined') { | ||
window.remoteScriptsOnReadyCalls ??= 0 | ||
window.inlineScriptsOnReadyCalls ??= 0 | ||
} | ||
|
||
const Page = () => { | ||
return ( | ||
<div className="container"> | ||
<Link href="/page9">Page 9</Link> | ||
<div id="text"></div> | ||
<Script | ||
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" | ||
onReady={() => { | ||
window.remoteScriptsOnReadyCalls++ | ||
}} | ||
/> | ||
<Script | ||
id="i-am-an-inline-script-that-has-on-ready" | ||
dangerouslySetInnerHTML={{ __html: 'console.log("inline script!")' }} | ||
onReady={() => { | ||
window.inlineScriptsOnReadyCalls++ | ||
}} | ||
/> | ||
</div> | ||
) | ||
} | ||
|
||
export default Page |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
reactStrictMode: true, | ||
} |
31 changes: 31 additions & 0 deletions
31
test/integration/script-loader/strictmode/pages/onready.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Script from 'next/script' | ||
import Link from 'next/link' | ||
|
||
if (typeof window !== 'undefined') { | ||
window.remoteScriptsOnReadyCalls ??= 0 | ||
window.inlineScriptsOnReadyCalls ??= 0 | ||
} | ||
|
||
const Page = () => { | ||
return ( | ||
<div className="container"> | ||
<Link href="/page9">Page 9</Link> | ||
<div id="text"></div> | ||
<Script | ||
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" | ||
onReady={() => { | ||
window.remoteScriptsOnReadyCalls++ | ||
}} | ||
/> | ||
<Script | ||
id="i-am-an-inline-script-that-has-on-ready" | ||
dangerouslySetInnerHTML={{ __html: 'console.log("inline script!")' }} | ||
onReady={() => { | ||
window.inlineScriptsOnReadyCalls++ | ||
}} | ||
/> | ||
</div> | ||
) | ||
} | ||
|
||
export default Page |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters