react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Bug]: `useLocation` out of sync with `history.location`, leads to potential renders of unmatched `Route`s

Open zefj opened this issue 1 year ago • 1 comments

What version of React Router are you using?

5.3.4 (but the same happens on v6)

Steps to Reproduce

Hey,

After upgrading to react@18, we started noticing unexpected renders of Routes that should no longer match. After some investigation we found that for a brief moment there's a discrepancy between what react-router thinks the pathname is, and what the browser thinks the pathname is. It looks like useLocation() and related are lagging behind createBrowserHistory().location as well as window.location - hence why I'm reporting this as a potential bug.

Our app is a rather old school React+Redux setup, and therefore relies heavily on navigation outside of the React context, primarily as a result of handling Redux actions - for example: dispatch an action -> perform http request -> redirect on complete. If the action performs a state update that the Route component subscribes to (such as a loading flag), it will do an extra render before unmounting, and during that render window.location.pathname will not match useLocation().pathname.

This was not happening in react@17. I ran the same experiment on react-router-dom@6 and got the same results. Unfortunately, it leads to some hard-to-find issues in code that for any reason relied on this behaviour, as well as some noticeable UX regressions where the additional render now causes unnecessary UI updates, and can delay the page transition.

See the links below that roughly simulate the setup that we have (excuse the occasional TS error). Open the browser console, then click the button and observe the console.logs:

  • react@17: https://stackblitz.com/edit/vitejs-vite-czwt3z?terminal=dev
  • react@18: https://stackblitz.com/edit/vitejs-vite-werwvr?terminal=dev

Screenshot 2024-04-18 at 14 39 08

Expected Behavior

useLocation().pathname and related should be consistent with createBrowserHistory().location.pathname as well as window.location.pathname. Routes that don't match should no longer render.

Actual Behavior

useLocation().pathname is stale compared to createBrowserHistory().location.pathname and window.location.pathname. Route component can render despite its path no longer matching.

zefj avatar Apr 18 '24 13:04 zefj

Unfortunately, version 7 has the same issue

notbucai avatar Jul 15 '25 13:07 notbucai