feat: add usePendingMatches hook - #7863
Conversation
Expose the router's pending matches reactively in the react, solid and vue adapters, mirroring useMatches over router.stores.pendingMatches. pendingMatches was selectable via useRouterState before the granular stores refactor; the store still exists but had no public reactive accessor. Closes TanStack#7859 Claude-Session: https://claude.ai/code/session_0194gnPcL2Vh2fiESjL4YdKZ
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds ChangesPending matches API
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Router
participant PendingMatchesHook
participant DestinationLoader
User->>Router: click destination link
Router->>PendingMatchesHook: expose destination pending match
PendingMatchesHook-->>User: selected destination pathname
Router->>DestinationLoader: await route loader
DestinationLoader-->>Router: resolve loader
Router->>PendingMatchesHook: clear pending matches
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/router/api/router/usePendingMatchesHook.md`:
- Around line 6-8: Update the usePendingMatches documentation to state that
destination RouteMatch objects are available during any in-flight navigation,
including navigations blocked by pending conditions, not only while loading.
Preserve the existing behavior description for resolved or idle navigations and
the useMatches reference.
- Around line 23-28: Update the `opts.structuralSharing` documentation in
`usePendingMatchesHook` so it is explicitly scoped to the React adapter rather
than presented as a universal option. Do not claim Solid or Vue support unless
their hook option types and implementations are updated to expose it.
In `@packages/solid-router/src/Matches.tsx`:
- Around line 233-234: Update the conditional return logic in Matches.tsx to
wrap the prev === undefined branch in curly braces, and replace the any cast on
replaceEqualDeep with UseMatchesResult to preserve strict typing.
In `@packages/vue-router/src/Matches.tsx`:
- Around line 311-314: Update the fallback branch in the Matches selection logic
to remove the any cast and use the appropriate strict TypeScript type for
matches, while preserving the existing opts.select behavior and return value.
In `@packages/vue-router/tests/Matches.test.tsx`:
- Around line 386-389: Remove the explicit Array<any> annotation from the select
callback in usePendingMatches and let TypeScript infer the matches parameter
type. Preserve the existing last-match pathname selection and empty-string
fallback.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ea2d10bb-f2e0-46b4-b7bd-50d732ddb506
📒 Files selected for processing (11)
docs/router/api/router.mddocs/router/api/router/usePendingMatchesHook.mdpackages/react-router/src/Matches.tsxpackages/react-router/src/index.tsxpackages/react-router/tests/Matches.test.tsxpackages/solid-router/src/Matches.tsxpackages/solid-router/src/index.tsxpackages/solid-router/tests/Matches.test.tsxpackages/vue-router/src/Matches.tsxpackages/vue-router/src/index.tsxpackages/vue-router/tests/Matches.test.tsx
…ructuralSharing Also rely on type inference for the select callback in the vue test. Claude-Session: https://claude.ai/code/session_0194gnPcL2Vh2fiESjL4YdKZ
Closes #7859
Since the granular stores refactor,
pendingMatchesis no longer part ofRouterState, so there is no public reactive way to read the matches of an in-flight navigation —useRouterState({ select: (s) => s.pendingMatches })no longer compiles. The data still exists onrouter.stores.pendingMatches(already a derived reactive store, cleared on commit), but nothing public subscribes to it.This PR adds a
usePendingMatcheshook mirroringuseMatchesoverrouter.stores.pendingMatches, in all three adapters:useMatches, includingselect,structuralSharingand the SSR short-circuitcreateMemo+replaceEqualDeep, same asuseMatchesuseStoreover the pending store, same asuseMatchesThe hook returns an empty array when no navigation is in flight.
Use case (from the issue): when migrating from react-router, reactively highlighting the destination navigation item from the pending matches'
staticDataas soon as navigation starts, before code-split chunks and loaders resolve — without reaching intorouter.storesand hand-rollinguseSyncExternalStoreover router events.Also included:
docs/router/api/router/usePendingMatchesHook.md, linked from the API indextest:eslint,test:typesandtest:unitpass for the three packages. Developed with AI assistance (Claude Code).Summary by CodeRabbit
usePendingMatchesfor React, Solid, and Vue to access destination route matches while navigation is in-flight.selectto derive custom values from pending matches.usePendingMatcheswith examples.