mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 18:17:31 +08:00
chore(StackManager): more upgrades for rr6
This commit is contained in:
@ -1,8 +1,10 @@
|
|||||||
import type { RouteInfo, StackContextState, ViewItem } from '@ionic/react';
|
import type { RouteInfo, StackContextState, ViewItem } from '@ionic/react';
|
||||||
import { RouteManagerContext, StackContext, generateId, getConfig } from '@ionic/react';
|
import { RouteManagerContext, StackContext, generateId, getConfig } from '@ionic/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Route } from 'react-router';
|
||||||
|
|
||||||
import { clonePageElement } from './clonePageElement';
|
import { clonePageElement } from './clonePageElement';
|
||||||
|
import { findRoutesNode } from './utils/findRoutesNode';
|
||||||
import { matchPath } from './utils/matchPath';
|
import { matchPath } from './utils/matchPath';
|
||||||
|
|
||||||
// TODO(FW-2959): types
|
// TODO(FW-2959): types
|
||||||
@ -135,16 +137,16 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Match the route element to render
|
// Match the route element to render
|
||||||
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
const enteringRoute = findRouteByRouteInfo(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we already have a view item for this route, update its element.
|
* If we already have a view item for this route, update its element.
|
||||||
* Otherwise, create a new view item for the route.
|
* Otherwise, create a new view item for the route.
|
||||||
*/
|
*/
|
||||||
if (enteringViewItem) {
|
if (enteringViewItem) {
|
||||||
enteringViewItem.reactElement = enteringRoute;
|
enteringViewItem.reactElement = enteringRoute.props.element;
|
||||||
} else if (enteringRoute) {
|
} else if (enteringRoute) {
|
||||||
enteringViewItem = this.context.createViewItem(this.id, enteringRoute, routeInfo);
|
enteringViewItem = this.context.createViewItem(this.id, enteringRoute.props.element, routeInfo);
|
||||||
this.context.addViewItem(enteringViewItem);
|
this.context.addViewItem(enteringViewItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,33 +521,48 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
|||||||
|
|
||||||
export default StackManager;
|
export default StackManager;
|
||||||
|
|
||||||
function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
/**
|
||||||
|
* Finds the `<Route />` node matching the current route info.
|
||||||
|
* If no `<Route />` can be matched, a fallback node is returned.
|
||||||
|
*/
|
||||||
|
function findRouteByRouteInfo(node: React.ReactNode, routeInfo: RouteInfo) {
|
||||||
let matchedNode: React.ReactNode;
|
let matchedNode: React.ReactNode;
|
||||||
for (const child of React.Children.toArray(node) as React.ReactElement[]) {
|
let fallbackNode: React.ReactNode;
|
||||||
const match = matchPath({
|
|
||||||
pathname: routeInfo.pathname,
|
|
||||||
componentProps: child.props,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (match) {
|
// `<Route />` nodes are rendered inside of a <Routes /> node
|
||||||
matchedNode = child;
|
const routesNode = findRoutesNode(node) ?? node;
|
||||||
break;
|
|
||||||
|
for (const child of React.Children.toArray(routesNode) as React.ReactElement[]) {
|
||||||
|
// Check if the child is a `<Route />` node
|
||||||
|
if (child.type === Route) {
|
||||||
|
const match = matchPath({
|
||||||
|
pathname: routeInfo.pathname,
|
||||||
|
componentProps: child.props,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
matchedNode = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchedNode) {
|
if (matchedNode) {
|
||||||
return matchedNode;
|
return matchedNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we haven't found a node
|
// If we haven't found a node
|
||||||
// try to find one that doesn't have a path or from prop, that will be our not found route
|
// try to find one that doesn't have a path prop, that will be our not found route
|
||||||
for (const child of React.Children.toArray(node) as React.ReactElement[]) {
|
for (const child of React.Children.toArray(routesNode) as React.ReactElement[]) {
|
||||||
if (!(child.props.path || child.props.from)) {
|
if (child.type === Route) {
|
||||||
matchedNode = child;
|
if (!child.props.path) {
|
||||||
break;
|
fallbackNode = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchedNode;
|
return matchedNode ?? fallbackNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchComponent(node: React.ReactElement, pathname: string, forceExact?: boolean) {
|
function matchComponent(node: React.ReactElement, pathname: string, forceExact?: boolean) {
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Routes } from 'react-router';
|
||||||
|
|
||||||
|
export const findRoutesNode = (node: React.ReactNode) => {
|
||||||
|
// The use of `<Routes />` is encouraged with React Router v6.
|
||||||
|
let routesNode: React.ReactNode;
|
||||||
|
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||||
|
if (child.type === Routes) {
|
||||||
|
routesNode = child;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (routesNode) {
|
||||||
|
// The childern of the `<Routes />` component are most likely
|
||||||
|
// (and should be) the `<Route />` components.
|
||||||
|
return (routesNode as React.ReactElement).props.children;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
Reference in New Issue
Block a user