-
-
Notifications
You must be signed in to change notification settings - Fork 177
Description
Issue
When navigating from a source route (i.e. /route-a) to a destination route (/route-b) after a promise, the component for the source route is re-rendered after the navigation - when the URL is already set to the destination.
Reproducing
I was able to reproduce this issue in a code sandbox: https://codesandbox.io/p/sandbox/exciting-wilson-l9sk9x
export default function App() {
return (
<Router>
<Switch>
<Route path="/" component={Root} />
<Route path="/route-a" component={PageA} />
<Route path="/route-b" component={PageB} />
</Switch>
</Router>
);
}
function PageA() {
console.log("PageA render, pathname:", window.location.pathname);
return (
<div>
<p>page A</p>
<button
onClick={() => {
Promise.resolve().then(() => {
navigate("/route-b");
});
}}
>
navigate after promise
</button>
<button
onClick={() => {
navigate("/route-b");
}}
>
navigate immediately
</button>
</div>
);
}
function PageB() {
return <div>page B</div>;
}
function Root() {
return (
<div>
<h1>Steps to repro</h1>
...
</div>
);
}- Go to
/route-a - Open the console
- Click
navigate after promise
The console will read:
PageA render, pathname: /route-a
PageA render, pathname: /route-b
This is unexpected, since PageA should only render on /route-a, not /route-b
If you repro with the following steps, the extra render does not occur:
- Go to
/route-a - Open the console
- Click
navigate immediately
The console will only read:
PageA render, pathname: /route-a
Which is what I would expect in both cases.
Why this is an issue
Say I have a condition in PageA to check for a search param (i.e. auth=1), and if it does not exist, navigate to an earlier route where the search param is populated. When navigating from /route-a to /route-b, I don't include the search param i.e. I would navigate from /route-a?auth=1 to /route-b , not /route-b?auth=1. When navigating after promise, PageA is re-rendered with the URL of /route-b. Since the auth=1 search param is not present, my condition kicks in, and I'm navigated away from the destination route. This is more or less the scenario that led me to root-cause this issue.
Notes
- I'm using the latest version of Wouter,
3.4.0 - When using React 18 with
createRoot, the extra render does not occur, see https://codesandbox.io/p/sandbox/musing-dust-qm6mlx