mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(react-router): parameterized routes create new instances
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 &&
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user