mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 02:31:34 +08:00
fix: mounting of pages
Notes: Push and Pop animations are not working. Swipe to go back isn't working. It isn't keeping the leaving view item in the DOM after pushing a new entering view item.
This commit is contained in:
@ -2,7 +2,7 @@ import type { Action as HistoryAction, History, Location as HistoryLocation } fr
|
|||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import type { BrowserRouterProps } from 'react-router-dom';
|
import type { BrowserRouterProps } from 'react-router-dom';
|
||||||
import { BrowserRouter, useLocation } from 'react-router-dom';
|
import { BrowserRouter, useLocation, useNavigationType } from 'react-router-dom';
|
||||||
|
|
||||||
import { IonRouter } from './IonRouter';
|
import { IonRouter } from './IonRouter';
|
||||||
|
|
||||||
@ -10,6 +10,9 @@ interface IonReactRouterProps extends BrowserRouterProps {
|
|||||||
history?: History;
|
history?: History;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `IonReactRouter` is Ionic's routing container component. It is a wrapper around `BrowserRouter` from `react-router-dom`.
|
||||||
|
*/
|
||||||
export const IonReactRouter = ({ children, ...rest }: PropsWithChildren<IonReactRouterProps>) => {
|
export const IonReactRouter = ({ children, ...rest }: PropsWithChildren<IonReactRouterProps>) => {
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
@ -18,8 +21,12 @@ export const IonReactRouter = ({ children, ...rest }: PropsWithChildren<IonReact
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browser router provides the context APIs for the hooks to work.
|
||||||
|
*/
|
||||||
const IonInnerReactRouter = ({ children }: PropsWithChildren<IonReactRouterProps>) => {
|
const IonInnerReactRouter = ({ children }: PropsWithChildren<IonReactRouterProps>) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const navigationType = useNavigationType();
|
||||||
|
|
||||||
const historyListenHandler = useRef<(location: HistoryLocation, action: HistoryAction) => void>();
|
const historyListenHandler = useRef<(location: HistoryLocation, action: HistoryAction) => void>();
|
||||||
|
|
||||||
@ -36,8 +43,8 @@ const IonInnerReactRouter = ({ children }: PropsWithChildren<IonReactRouterProps
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleHistoryChange(location, 'POP'); // TODO @sean unsure about this
|
handleHistoryChange(location, navigationType);
|
||||||
}, [location]);
|
}, [location, navigationType]);
|
||||||
|
|
||||||
return <IonRouter registerHistoryListener={registerHistoryListener}>{children}</IonRouter>;
|
return <IonRouter registerHistoryListener={registerHistoryListener}>{children}</IonRouter>;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import type { RouteInfo, ViewItem } from '@ionic/react';
|
import type { RouteInfo, ViewItem } from '@ionic/react';
|
||||||
import { IonRoute, ViewLifeCycleManager, ViewStacks, generateId } from '@ionic/react';
|
import { IonRoute, ViewLifeCycleManager, ViewStacks, generateId } from '@ionic/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Routes } from 'react-router';
|
import { Route } from 'react-router';
|
||||||
|
|
||||||
|
import { findRoutesNode } from './utils/findRoutesNode';
|
||||||
import { matchPath } from './utils/matchPath';
|
import { matchPath } from './utils/matchPath';
|
||||||
|
|
||||||
export class ReactRouterViewStack extends ViewStacks {
|
export class ReactRouterViewStack extends ViewStacks {
|
||||||
@ -45,12 +46,14 @@ export class ReactRouterViewStack extends ViewStacks {
|
|||||||
const viewItems = this.getViewItemsForOutlet(outletId);
|
const viewItems = this.getViewItemsForOutlet(outletId);
|
||||||
|
|
||||||
// Sync latest routes with viewItems
|
// Sync latest routes with viewItems
|
||||||
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
|
React.Children.forEach(findRoutesNode(ionRouterOutlet.props.children), (child: React.ReactElement) => {
|
||||||
const viewItem = viewItems.find((v) => {
|
if (child.type === Route) {
|
||||||
return matchComponent(child, v.routeData.childProps.path || v.routeData.childProps.from);
|
const viewItem = viewItems.find((v) => {
|
||||||
});
|
return matchComponent(child, v.routeData.childProps.path || v.routeData.childProps.from);
|
||||||
if (viewItem) {
|
});
|
||||||
viewItem.reactElement = child;
|
if (viewItem) {
|
||||||
|
viewItem.reactElement = child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,11 +64,9 @@ export class ReactRouterViewStack extends ViewStacks {
|
|||||||
mount={viewItem.mount}
|
mount={viewItem.mount}
|
||||||
removeView={() => this.remove(viewItem)}
|
removeView={() => this.remove(viewItem)}
|
||||||
>
|
>
|
||||||
<Routes>
|
{React.cloneElement(viewItem.reactElement, {
|
||||||
{React.cloneElement(viewItem.reactElement, {
|
computedMatch: viewItem.routeData.match,
|
||||||
computedMatch: viewItem.routeData.match,
|
})}
|
||||||
})}
|
|
||||||
</Routes>
|
|
||||||
</ViewLifeCycleManager>
|
</ViewLifeCycleManager>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -113,9 +115,9 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
|||||||
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +135,7 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
|||||||
* If the route data does not match the current path, the parent router outlet
|
* If the route data does not match the current path, the parent router outlet
|
||||||
* is attempting to transition and we cancel the operation.
|
* is attempting to transition and we cancel the operation.
|
||||||
*/
|
*/
|
||||||
if (enteringViewItem.routeData.match.url !== routeInfo.pathname) {
|
if (enteringViewItem.routeData.match.pathname !== routeInfo.pathname) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,13 +434,18 @@ export default StackManager;
|
|||||||
|
|
||||||
function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
||||||
let matchedNode: React.ReactNode;
|
let matchedNode: React.ReactNode;
|
||||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
|
||||||
const match = matchPath({
|
const routesNode = findRoutesNode(node) ?? node;
|
||||||
pathname: routeInfo.pathname,
|
|
||||||
componentProps: child.props,
|
React.Children.forEach(routesNode, (child: React.ReactElement) => {
|
||||||
});
|
if (child.type === Route) {
|
||||||
if (match) {
|
const match = matchPath({
|
||||||
matchedNode = child;
|
pathname: routeInfo.pathname,
|
||||||
|
componentProps: child.props,
|
||||||
|
});
|
||||||
|
if (match) {
|
||||||
|
matchedNode = child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -447,9 +454,11 @@ function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
|||||||
}
|
}
|
||||||
// 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 or from prop, that will be our not found route
|
||||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
React.Children.forEach(routesNode, (child: React.ReactElement) => {
|
||||||
if (!(child.props.path || child.props.from)) {
|
if (child.type === Route) {
|
||||||
matchedNode = child;
|
if (!(child.props.path || child.props.from)) {
|
||||||
|
matchedNode = child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Routes } from "react-router";
|
||||||
|
|
||||||
|
export const findRoutesNode = (node: React.ReactNode) => {
|
||||||
|
// Finds the <Routes /> component node
|
||||||
|
let routesNode: React.ReactNode;
|
||||||
|
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||||
|
if (child.type === Routes) {
|
||||||
|
routesNode = child;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (routesNode) {
|
||||||
|
return (routesNode as React.ReactElement).props.children;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
Reference in New Issue
Block a user