fix: ensure child routes receive context returned from parent routes' beforeLoad
functions, even if invalidate()
is called during another load
#4306
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Possibly related:
beforeLoad
,loader
andvalidateSearch
#3578I've been struggling with an issue where a parent route's context, as returned by
beforeLoad
, is missing (as in completely empty) in a child route, in certain circumstances, particular immediately after logging in. The types suggest this should be impossible, but there are circumstances in where it happens.This PR adds a failing e2e test that reproduces the issue, and a tentative fix to the router itself.
Details
To add authentication to the router context, I'm passing a
context
prop into<RouterProvider>
. This context is stored in React state, contains the current user, and is updated after login.Also, in order to get ensure that the routes are re-loaded after log out, I've added a call to
router.invalidate()
in an effect within the same component.This works as expected when logging out. However, after logging in, the router is calling the
loader()
function of the new page without the context injected by its parent route'sbeforeLoad()
function. In my app, this causes an error to be logged to the console on the first run through, and causes the app to crash on the second. This behavior is repeated in the e2e test I've added here.Adding
console.log()
statements in various places, I've noticed that thebeforeLoad()
function is running before the child loader is called, so it's not that the context isn't available, it's just not being passed in.While debugging, I noticed that
invalidate()
callsrouter.load()
, even when the router is already loading, e.g. because of anavigate()
call being made after login.router/packages/router-core/src/router.ts
Lines 2797 to 2827 in 9db424f
I noticed that adding a guard to this
router.load()
, so that it is only called if the router is not already loading, fixed my issue, but I worry it would introduce further bugs down the track.So the fix I ended up arriving on is to use the existing
latestLoadPromise
to wait for previousrouter.load()
calls to complete before starting a new one, which resolved the issue for me, and got the new e2e test that I've added passing.