chore(StackManager): more upgrades for rr6

This commit is contained in:
Maria Hutt
2025-05-19 14:01:54 -07:00
parent 4aad76a93a
commit fd6baaceda
2 changed files with 54 additions and 18 deletions

View File

@ -1,8 +1,10 @@
import type { RouteInfo, StackContextState, ViewItem } from '@ionic/react';
import { RouteManagerContext, StackContext, generateId, getConfig } from '@ionic/react';
import React from 'react';
import { Route } from 'react-router';
import { clonePageElement } from './clonePageElement';
import { findRoutesNode } from './utils/findRoutesNode';
import { matchPath } from './utils/matchPath';
// TODO(FW-2959): types
@ -135,16 +137,16 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
}
// 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.
* Otherwise, create a new view item for the route.
*/
if (enteringViewItem) {
enteringViewItem.reactElement = enteringRoute;
enteringViewItem.reactElement = enteringRoute.props.element;
} 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);
}
@ -519,33 +521,48 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
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;
for (const child of React.Children.toArray(node) as React.ReactElement[]) {
const match = matchPath({
pathname: routeInfo.pathname,
componentProps: child.props,
});
let fallbackNode: React.ReactNode;
if (match) {
matchedNode = child;
break;
// `<Route />` nodes are rendered inside of a <Routes /> node
const routesNode = findRoutesNode(node) ?? node;
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) {
return matchedNode;
}
// 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
for (const child of React.Children.toArray(node) as React.ReactElement[]) {
if (!(child.props.path || child.props.from)) {
matchedNode = child;
break;
// 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(routesNode) as React.ReactElement[]) {
if (child.type === Route) {
if (!child.props.path) {
fallbackNode = child;
break;
}
}
}
return matchedNode;
return matchedNode ?? fallbackNode;
}
function matchComponent(node: React.ReactElement, pathname: string, forceExact?: boolean) {

View File

@ -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;
};