fix: include loader identity and params in loader cache key#224
Merged
Conversation
Loader cache keys were `${entryKey}:${matchIndex}`, carrying no route
identity. Whenever the same navigation entry mapped to a different route
stack — a dynamic `routes` prop (feature flags, permission-dependent
routes) or two <Router> instances on one page — a different route
matching at the same index was served the previous route's cached loader
result instead of running its own loader.
Cache keys now also include the identity of the loader function (issued
lazily via a WeakMap) and the matched params. The loader function is
used as the identity — rather than the route definition object — because
a cached result is fully determined by the loader and its args: swapping
in a route variant with a different loader re-executes it, while route
definitions recreated across renders keep their cached results as long
as they reference the same loader function. Params are included so a
shared loader reached via a different path pattern (e.g. `/:page` vs
`/:section`) does not serve a result computed with different params.
Fixes #207
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018waJv8AuctJWHBBWWkqTd5
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fixes #207
Problem
Loader cache keys were
${entryKey}:${matchIndex}, carrying no route identity. Whenever the same navigation entry mapped to a different route stack, the wrong cached data was served:routesprop (feature flags, permission-dependent routes): a different route matching at the same index got the previous route's cached loader result instead of running its own loader.<Router>instances on one page: both share the module-level cache and the same navigation entry, so their keys collided.Fix
Cache keys are now
${entryKey}:${matchIndex}:${loaderId}:${paramsKey}, whereloaderIdis a lazily-issuedWeakMapid on the loader function andparamsKeyis the serialized matched params.Why loader-function identity (not the route definition object or the path pattern)
pathwith different loaders, so pattern-keyed entries would still serve stale data.ssrLoaderCache.test.tsx): route definitions recreated across renders must keep their cached results. Object-identity keying would make inline-created routes re-execute loaders on every parent re-render.Params are included in the key so the same loader function reached via a different path pattern (e.g.
/:pagevs/:section) does not serve a result computed with different params for the same URL.The prefix-based cache flows are unaffected since keys still start with the entry key: same-URL replace carry-over, form-submission revalidation, reload generations, and dispose cleanup all work unchanged.
Tests
New
dynamicRoutes.test.tsxwith 7 tests:<Router>instances on one page don't share loader dataDocs
Updated the "How Loaders Run" page: the caching section now describes the full cache identity, with a new "Changing the Routes Prop" subsection documenting the dynamic-routes behavior.
🤖 Generated with Claude Code
https://claude.ai/code/session_018waJv8AuctJWHBBWWkqTd5
Generated by Claude Code