Skip to content

fix(react-router): stop hidden views from re-rendering on every navigation - #31541

Merged
ShaneK merged 2 commits into
mainfrom
FW-7824
Oct 8, 2026
Merged

ShaneK merged 2 commits into
mainfrom
FW-7824

Conversation

@ShaneK

@ShaneK ShaneK commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Issue number: resolves #31528


What is the current behavior?

Currently, every mounted view in an IonRouterOutlet re-renders on each navigation, hidden ones included. The view stack builds a new RouteContext value every time the outlet renders, which happens about 3 times per navigation, and NavManager does the same with NavContext and IonRouterContext.

What is the new behavior?

We now keep each view's RouteContext value until its content changes, and a view whose route doesn't match the current location keeps the value it last rendered with. Hidden pages using useParams no longer re-render, and the page being shown renders once when its match changes. The NavManager also only rebuilds its context values when routeInfo changes, so useIonRouter consumers render once per navigation instead of twice.

Does this introduce a breaking change?

  • Yes
  • No

Other information

The held value lives in a component under each view instead of on the view item, because two outlets with the same id share a view item while sitting under different parent routes.

Hidden pages using useNavigate or useLocation still render once per navigation, because React Router's useNavigate reads the location internally. Holding LocationContext would fix that, but useLocation() in a hidden page would then return a stale location, so I left that alone for now.

Current dev build

9.0.7-dev.11791381676.118a7a15

@ShaneK
ShaneK requested a review from a team as a code owner October 7, 2026 13:59
@ShaneK
ShaneK requested a review from thetaPC October 7, 2026 13:59
@vercel

vercel Bot commented Oct 7, 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 Oct 8, 2026 6:04pm 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, minor question

const { matches: aMatches, ...aRest } = a;
const { matches: bMatches, ...bRest } = b;
return (
shallowEqual(aRest, bRest) &&

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.

Would it be better to check for length first so shallowEqual doesn't have to run if the easy length check fails?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Sure, I guess. It's technically more correct, but the difference in order here can only ever be so little that it's negligible. Still, since it's more technically correct, I went ahead an changed the order: 159e920

<ParamsReader tab={tab} />
<IonRouterReader tab={tab} />
<TestDescription>
Switch between Tabs A, B and C a few times. Hidden pages that read useParams should not re-render, and ones

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.

Thank you for adding why this page exists! Same for the rest.

@ShaneK
ShaneK enabled auto-merge October 8, 2026 18:00
@ShaneK
ShaneK added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit 4ae0196 Oct 8, 2026
56 checks passed
@ShaneK
ShaneK deleted the FW-7824 branch October 8, 2026 18:27

This branch was successfully deployed

1 active deployment
Preview — 159e9200 Deployed Oct 8, 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): every mounted view re-renders on each navigation through a new RouteContext value

2 participants