Make PendingNavigation.tsx strict-mode-compatible#12310
Conversation
We found that PendingNavigation.tsx was NOT strict-mode-compatible out of the box. As `shouldComponentUpdate` (and thus `dispatchLifecycleAction(...)`) is double-invoked in development-mode (when we export StrictMode as default in src/theme/Root.js), this would be a terrible experience during development mode (even though it does not affect production builds). (For example, the progress bar is still displayed at the top even though navigation was finished because that lifecycle method was double-invoked.) To address this problem, we use a field `this.pendingLocation` to track the location that is being preloaded. During the second synchronous render pass (when StrictMode in development), we compare the `nextProps.location` against `this.pendingLocation` and if they match, this returns `false` immediately, which causes the `dispatchLifecycleAction(...)` to not run more than one time. Beyond this fix, this commit also has the added benefit of the following: Checking `if (this.pendingLocation === nextLocation)` inside the asynchronous `.then()` block acts as an **abort-and-debounce guard**. If a user rapidly double-clicks different links (e.g., navigating to Page A and then quickly to Page B), the preloading of Page A will resolve but won't trigger state updates or prematurely (for example) dismiss the progress bar for Page B. * NOTE: parts of these code changes and/or the text of this commit were made using AI Signed-off-by: seyoon20087 <24852454+seyoon20087@users.noreply.github.com>
✅ [V2]Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
How did you find out? We don't have a strict mode setting in Docusaurus (yet). If this is something detected and implemented by AI, please disclose it properly or explain how to reproduce the issues you encountered in a concrete way. Note that refactoring this without asking me first is not a good idea. We are not even sure to keep this component in v4, see #12201 |
Sorry about this. First, I created a new site (yarn create docusaurus), and in src/theme/Root.js add these contents: export { StrictMode as default } from "react";with the original 'PendingNavigation.tsx', when add that file, this is the video of the demonstration: Screen.Recording.2026-07-23.at.6.48.26.PM.movA progress bar is displayed even though navigation was completed. (I expected that the progress bar isn't displayed) |
We found that PendingNavigation.tsx was NOT strict-mode-compatible out of the box.
As
shouldComponentUpdate(and thusdispatchLifecycleAction(...)) is double-invoked in development-mode(when we export StrictMode as default in src/theme/Root.js), this would be a terrible experience during development mode (even though it does not affect production builds).
(For example, the progress bar is still displayed at the top even though navigation was finished because that lifecycle method was double-invoked.)
To address this problem, we use a field
this.pendingLocationto track the location that is being preloaded.During the second synchronous render pass (when StrictMode in development), we compare the
nextProps.locationagainstthis.pendingLocationand if they match, this returnsfalseimmediately, which causes thedispatchLifecycleAction(...)to not run more than one time.Beyond this fix, this commit also has the added benefit of the following:
Checking
if (this.pendingLocation === nextLocation)inside the asynchronous.then()block acts as an abort-and-debounce guard.If a user rapidly double-clicks different links (e.g., navigating to Page A and then quickly to Page B), the preloading of Page A will resolve but won't trigger state updates or prematurely (for example) dismiss the progress bar for Page B.
NOTE: parts of these code changes and/or the text of this commit were made using AI
Pre-flight checklist
Motivation
Test Plan
Test links
Deploy preview: https://deploy-preview-_____--docusaurus-2.netlify.app/
Related issues/PRs
Alternate fix for #10037