Skip to content

fix(react-router): keep splat route page mounted when a sibling route is pushed - #31481

Merged
ShaneK merged 8 commits into
mainfrom
fix/rr6-route-bug
Sep 28, 2026
Merged

ShaneK merged 8 commits into
mainfrom
fix/rr6-route-bug

Conversation

@ShaneK

@ShaneK ShaneK commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Issue number: resolves #31477


What is the current behavior?

Currently, an outlet holding a splat route alongside a more specific sibling loses the splat's page when you push that sibling. A splat matches every pathname, so findViewItems hands back its view item for a pathname the sibling owns, and handlePageTransition then overwrites that item's reactElement, which swaps the page and unmounts it. Whatever was underneath, usually tabs or a nested outlet, is destroyed along with its state and scroll position.

A root-level /* has two further problems. Going back blanks the whole outlet, because getParentPath caches an inferred outletMountPath on the root outlet, which scopes it to whatever route was active and makes the next pathname look out of scope, so handleOutOfScopeOutlet aborts the transition and tears the outlet down. Swipe-to-go-back does nothing, because the deactivation scan in renderViewItem re-applies ion-page-hidden on the next render and undoes revealIonPageForSwipeBack, leaving the user dragging a page with display: none.

What is the new behavior?

handlePageTransition now compares the view item it found against findRouteByRouteInfo, which is React Router's own ranking, and drops it when the two disagree so a fresh view item gets created for the winning route. The catch-all deactivation no longer unmounts a view that was pushed over, since hiding it is enough to keep it from rendering alongside the pushed page. A root outlet no longer caches a mount path, in both places that were doing it, because it is mounted under nothing and an inferred path only scopes it wrongly. The deactivation scan also skips whichever page a swipe gesture is currently revealing, tracked in a WeakSet that is marked in onStart and cleared when the gesture ends.

Does this introduce a breaking change?

  • Yes
  • No

Other information

New test pages:

Current Dev Build

9.0.6-dev.11790349282.1a877abd

@ShaneK
ShaneK requested a review from a team as a code owner September 24, 2026 20:11
@ShaneK
ShaneK requested a review from OS-jacobbell September 24, 2026 20:11
@vercel

vercel Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ionic-framework Ready Ready Preview Sep 28, 2026 5:35pm UTC

Request Review

@thetaPC thetaPC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread packages/react-router/src/ReactRouter/StackManager.tsx Outdated
@ShaneK
ShaneK added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 1130c2c Sep 28, 2026
56 checks passed
@ShaneK
ShaneK deleted the fix/rr6-route-bug branch September 28, 2026 17:59

This branch was successfully deployed

1 active deployment
Preview — bd704be3 Deployed Sep 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: react @ionic/react package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: react-router, a /* route is overwritten by a more specific sibling route and its page is unmounted

2 participants