Skip to content

Commit e6def6b

Browse files
committed
fix(react-router): replacing a lot of our custom logic with internal RR6 APIs to do the heavy lifting and fix routing bugs
1 parent 88d0e70 commit e6def6b

File tree

12 files changed

+480
-259
lines changed

12 files changed

+480
-259
lines changed

packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ export class ReactRouterViewStack extends ViewStacks {
282282
if (hasParams) {
283283
if (isWildcard) {
284284
const existingPathnameBase = v.routeData?.match?.pathnameBase;
285-
const newMatch = matchComponent(reactElement, routeInfo.pathname, false);
285+
const newMatch = matchComponent(reactElement, routeInfo.pathname, false, this.outletParentPaths.get(outletId));
286286
const newPathnameBase = newMatch?.pathnameBase;
287287
if (existingPathnameBase !== newPathnameBase) {
288288
return false;
@@ -309,7 +309,7 @@ export class ReactRouterViewStack extends ViewStacks {
309309
existingViewItem.mount = true;
310310
existingViewItem.ionPageElement = page || existingViewItem.ionPageElement;
311311
const updatedMatch =
312-
matchComponent(reactElement, routeInfo.pathname, false) ||
312+
matchComponent(reactElement, routeInfo.pathname, false, this.outletParentPaths.get(outletId)) ||
313313
existingViewItem.routeData?.match ||
314314
createDefaultMatch(routeInfo.pathname, reactElement.props);
315315

@@ -337,7 +337,7 @@ export class ReactRouterViewStack extends ViewStacks {
337337
}
338338

339339
const initialMatch =
340-
matchComponent(reactElement, routeInfo.pathname, true) ||
340+
matchComponent(reactElement, routeInfo.pathname, true, this.outletParentPaths.get(outletId)) ||
341341
createDefaultMatch(routeInfo.pathname, reactElement.props);
342342

343343
viewItem.routeData = {
@@ -360,7 +360,7 @@ export class ReactRouterViewStack extends ViewStacks {
360360
*/
361361
private renderViewItem = (viewItem: ViewItem, routeInfo: RouteInfo, parentPath?: string, reRender?: () => void) => {
362362
const routePath = viewItem.reactElement.props.path || '';
363-
let match = matchComponent(viewItem.reactElement, routeInfo.pathname);
363+
let match = matchComponent(viewItem.reactElement, routeInfo.pathname, false, parentPath);
364364

365365
if (!match) {
366366
const indexMatch = resolveIndexRouteMatch(viewItem, routeInfo.pathname, parentPath);
@@ -593,10 +593,18 @@ export class ReactRouterViewStack extends ViewStacks {
593593
outletId: string,
594594
ionRouterOutlet: React.ReactElement,
595595
routeInfo: RouteInfo,
596-
reRender: () => void
596+
reRender: () => void,
597+
parentPathnameBase?: string
597598
) => {
598599
const viewItems = this.getViewItemsForOutlet(outletId);
599600

601+
// Seed the mount path from the parent route context if available.
602+
// This provides the outlet's mount path immediately on first render,
603+
// eliminating the need for heuristic-based discovery in computeParentPath.
604+
if (parentPathnameBase && !this.outletMountPaths.has(outletId)) {
605+
this.outletMountPaths.set(outletId, parentPathnameBase);
606+
}
607+
600608
// Determine parentPath for outlets with relative or index routes.
601609
// This populates outletParentPaths for findViewItemByPath's matchView
602610
// and the catch-all deactivation logic in renderViewItem.
@@ -680,7 +688,7 @@ export class ReactRouterViewStack extends ViewStacks {
680688
const viewRoutePath = viewItem.reactElement?.props?.path as string | undefined;
681689
if (viewRoutePath) {
682690
// First try exact match using matchComponent
683-
const routeMatch = matchComponent(viewItem.reactElement, routeInfo.pathname);
691+
const routeMatch = matchComponent(viewItem.reactElement, routeInfo.pathname, false, parentPath);
684692
if (routeMatch) {
685693
// View matches current route, keep it
686694
return true;
@@ -794,10 +802,10 @@ export class ReactRouterViewStack extends ViewStacks {
794802

795803
const isIndexRoute = !!v.routeData.childProps.index;
796804
const previousMatch = v.routeData?.match;
797-
const result = v.reactElement ? matchComponent(v.reactElement, pathname) : null;
805+
const outletParentPath = storedParentPaths.get(v.outletId);
806+
const result = v.reactElement ? matchComponent(v.reactElement, pathname, false, outletParentPath) : null;
798807

799808
if (!result) {
800-
const outletParentPath = storedParentPaths.get(v.outletId);
801809
const indexMatch = resolveIndexRouteMatch(v, pathname, outletParentPath);
802810
if (indexMatch) {
803811
match = indexMatch;
@@ -977,10 +985,21 @@ export class ReactRouterViewStack extends ViewStacks {
977985
/**
978986
* Utility to apply matchPath to a React element and return its match state.
979987
*/
980-
function matchComponent(node: React.ReactElement, pathname: string, allowFallback = false) {
988+
function matchComponent(node: React.ReactElement, pathname: string, allowFallback = false, parentPath?: string) {
981989
const routeProps = node?.props ?? {};
982990
const routePath: string | undefined = routeProps.path;
983-
const pathnameToMatch = derivePathnameToMatch(pathname, routePath);
991+
992+
let pathnameToMatch: string;
993+
if (parentPath && routePath && !routePath.startsWith('/')) {
994+
// When parent path is known, compute exact relative pathname
995+
// instead of using the tail-slice heuristic
996+
const relative = pathname.startsWith(parentPath)
997+
? pathname.slice(parentPath.length).replace(/^\//, '')
998+
: pathname;
999+
pathnameToMatch = relative;
1000+
} else {
1001+
pathnameToMatch = derivePathnameToMatch(pathname, routePath);
1002+
}
9841003

9851004
const match = matchPath({
9861005
pathname: pathnameToMatch,

0 commit comments

Comments
 (0)