Skip to content

Commit

Permalink
fix(react-router): parameterized routes create new instances
Browse files Browse the repository at this point in the history
  • Loading branch information
sean-perkins committed Jan 19, 2023
1 parent 6d4c52a commit 7f2685c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 12 deletions.
1 change: 1 addition & 0 deletions packages/react-router/src/ReactRouter/IonRouter.tsx
Expand Up @@ -44,6 +44,7 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
createViewItem: this.viewStack.createViewItem,
findViewItemByRouteInfo: this.viewStack.findViewItemByRouteInfo,
findLeavingViewItemByRouteInfo: this.viewStack.findLeavingViewItemByRouteInfo,
findRouteMatchByRouteInfo: this.viewStack.findRouteMatchByRouteInfo,
addViewItem: this.viewStack.add,
unMountViewItem: this.viewStack.remove,
};
Expand Down
14 changes: 8 additions & 6 deletions packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx
Expand Up @@ -11,6 +11,7 @@ export class ReactRouterViewStack extends ViewStacks {
this.findLeavingViewItemByRouteInfo = this.findLeavingViewItemByRouteInfo.bind(this);
this.getChildrenToRender = this.getChildrenToRender.bind(this);
this.findViewItemByPathname = this.findViewItemByPathname.bind(this);
this.findRouteMatchByRouteInfo = this.findRouteMatchByRouteInfo.bind(this);
}

createViewItem(outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement) {
Expand Down Expand Up @@ -96,12 +97,8 @@ export class ReactRouterViewStack extends ViewStacks {
return children;
}

findViewItemByRouteInfo(routeInfo: RouteInfo, outletId?: string, updateMatch?: boolean) {
const { viewItem, match } = this.findViewItemByPath(routeInfo.pathname, outletId);
const shouldUpdateMatch = updateMatch === undefined || updateMatch === true;
if (shouldUpdateMatch && viewItem && match) {
viewItem.routeData.match = match;
}
findViewItemByRouteInfo(routeInfo: RouteInfo, outletId?: string) {
const { viewItem } = this.findViewItemByPath(routeInfo.pathname, outletId);
return viewItem;
}

Expand All @@ -115,6 +112,11 @@ export class ReactRouterViewStack extends ViewStacks {
return viewItem;
}

findRouteMatchByRouteInfo(routeInfo: RouteInfo, outletId?: string) {
const { match } = this.findViewItemByPath(routeInfo.pathname, outletId);
return match;
}

private findViewItemByPath(pathname: string, outletId?: string, forceExact?: boolean, mustBeIonRoute?: boolean) {
let viewItem: ViewItem | undefined;
let match: ReturnType<typeof matchPath> | undefined;
Expand Down
43 changes: 38 additions & 5 deletions packages/react-router/src/ReactRouter/StackManager.tsx
Expand Up @@ -93,6 +93,22 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
let enteringViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);
let leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id);

let recreateEnteringView = false;

if (routeInfo.prevRouteLastPathname) {
let prevRouteViewItem = this.context.findViewItemByPathname(routeInfo.prevRouteLastPathname, this.id);
if (prevRouteViewItem) {
if (prevRouteViewItem === enteringViewItem && prevRouteViewItem.routeData.match.url !== routeInfo.pathname) {
recreateEnteringView = true;
}
}
}

const match = this.context.findRouteMatchByRouteInfo(routeInfo, this.id);
if (enteringViewItem && match) {
enteringViewItem.routeData.match = match;
}

if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
leavingViewItem = this.context.findViewItemByPathname(routeInfo.prevRouteLastPathname, this.id);
}
Expand All @@ -113,6 +129,23 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;

if (enteringViewItem) {
const match = this.context.findRouteMatchByRouteInfo(routeInfo, this.id);

if (match) {
enteringViewItem.routeData.match = match;
}
/**
* If we are re-entering a view item, then we need to validate that the
* view item is valid for the current route. For example, if the user navigates
* to a parametrized route: /foo/:id, then navigates to /example, then navigates
* back to /foo/:id, we only want to re-use the view item if the id param is the same.
* Otherwise we need to construct a new view item.
*/
if (recreateEnteringView) {
enteringViewItem = this.context.createViewItem(this.id, enteringRoute, routeInfo);
this.context.addViewItem(enteringViewItem);
}

enteringViewItem.reactElement = enteringRoute;
} else if (enteringRoute) {
enteringViewItem = this.context.createViewItem(this.id, enteringRoute, routeInfo);
Expand Down Expand Up @@ -223,7 +256,7 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
? this.prevProps.routeInfo
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id);

return (
!!enteringViewItem &&
Expand Down Expand Up @@ -253,8 +286,8 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
? this.prevProps.routeInfo
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id);
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);

/**
* When the gesture starts, kick off
Expand Down Expand Up @@ -284,8 +317,8 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
? this.prevProps.routeInfo
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id);
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);

/**
* Ionic React has a design defect where it
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/routing/RouteManagerContext.ts
Expand Up @@ -16,7 +16,8 @@ export interface RouteManagerContextState {
) => ViewItem;
findViewItemByPathname(pathname: string, outletId?: string): ViewItem | undefined;
findLeavingViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined;
findViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string, updateMatch?: boolean) => ViewItem | undefined;
findViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined;
findRouteMatchByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => any | undefined;
getChildrenToRender: (
outletId: string,
ionRouterOutlet: React.ReactElement,
Expand All @@ -36,6 +37,7 @@ export const RouteManagerContext = /*@__PURE__*/ React.createContext<RouteManage
findViewItemByPathname: () => undefined,
findLeavingViewItemByRouteInfo: () => undefined,
findViewItemByRouteInfo: () => undefined,
findRouteMatchByRouteInfo: () => undefined,
getChildrenToRender: () => undefined as any,
goBack: () => undefined,
unMountViewItem: () => undefined,
Expand Down

0 comments on commit 7f2685c

Please sign in to comment.