mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 01:03:03 +08:00
fix(react): support navigating to same page and route updates in IonRouterOutlet, fixes #19891, #19892, #19986
This commit is contained in:
@ -2,22 +2,24 @@ import React from 'react';
|
||||
|
||||
import { generateId, isDevMode } from '../utils';
|
||||
|
||||
import { RouteManagerContext } from './RouteManagerContext';
|
||||
import { RouteManagerContext, RouteManagerContextState } from './RouteManagerContext';
|
||||
import { View } from './View';
|
||||
import { ViewItem } from './ViewItem';
|
||||
import { ViewTransitionManager } from './ViewTransitionManager';
|
||||
|
||||
interface StackManagerProps {
|
||||
id?: string;
|
||||
routeManager: RouteManagerContextState;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
interface StackManagerState {
|
||||
routerOutletReady: boolean;
|
||||
}
|
||||
|
||||
export class StackManager extends React.Component<StackManagerProps, StackManagerState> {
|
||||
class StackManagerInner extends React.Component<StackManagerProps, StackManagerState> {
|
||||
routerOutletEl: React.RefObject<HTMLIonRouterOutletElement> = React.createRef();
|
||||
context!: React.ContextType<typeof RouteManagerContext>;
|
||||
|
||||
id: string;
|
||||
|
||||
constructor(props: StackManagerProps) {
|
||||
@ -31,7 +33,7 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.context.setupIonRouter(this.id, this.props.children, this.routerOutletEl.current!);
|
||||
this.props.routeManager.setupIonRouter(this.id, this.props.children, this.routerOutletEl.current!);
|
||||
this.routerOutletEl.current!.addEventListener('routerOutletReady', () => {
|
||||
this.setState({
|
||||
routerOutletReady: true
|
||||
@ -39,33 +41,39 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
|
||||
});
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: StackManagerProps, state: StackManagerState) {
|
||||
props.routeManager.syncRoute('', props.children);
|
||||
return state;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.context.removeViewStack(this.id);
|
||||
this.props.routeManager.removeViewStack(this.id);
|
||||
}
|
||||
|
||||
handleViewSync(page: HTMLElement, viewId: string) {
|
||||
this.context.syncView(page, viewId);
|
||||
this.props.routeManager.syncView(page, viewId);
|
||||
}
|
||||
|
||||
handleHideView(viewId: string) {
|
||||
this.context.hideView(viewId);
|
||||
this.props.routeManager.hideView(viewId);
|
||||
}
|
||||
|
||||
renderChild(item: ViewItem) {
|
||||
const component = React.cloneElement(item.route, {
|
||||
renderChild(item: ViewItem, route: any) {
|
||||
const component = React.cloneElement(route, {
|
||||
computedMatch: item.routeData.match
|
||||
});
|
||||
return component;
|
||||
}
|
||||
|
||||
render() {
|
||||
const context = this.context;
|
||||
const viewStack = context.viewStacks.get(this.id);
|
||||
const routeManager = this.props.routeManager;
|
||||
const viewStack = routeManager.viewStacks.get(this.id);
|
||||
const views = (viewStack || { views: [] }).views.filter(x => x.show);
|
||||
const ionRouterOutlet = React.Children.only(this.props.children) as React.ReactElement;
|
||||
const { routerOutletReady } = this.state;
|
||||
|
||||
const childElements = routerOutletReady ? views.map(view => {
|
||||
const route = routeManager.getRoute(view.routeId);
|
||||
return (
|
||||
<ViewTransitionManager
|
||||
id={view.id}
|
||||
@ -76,8 +84,9 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
|
||||
onViewSync={this.handleViewSync}
|
||||
onHideView={this.handleHideView}
|
||||
view={view}
|
||||
route={route}
|
||||
>
|
||||
{this.renderChild(view)}
|
||||
{this.renderChild(view, route)}
|
||||
</View>
|
||||
</ViewTransitionManager>
|
||||
);
|
||||
@ -99,8 +108,14 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
|
||||
|
||||
return routerOutletChild;
|
||||
}
|
||||
}
|
||||
|
||||
static get contextType() {
|
||||
return RouteManagerContext;
|
||||
}
|
||||
}
|
||||
const withContext = (Component: any) => {
|
||||
return (props: any) => (
|
||||
<RouteManagerContext.Consumer>
|
||||
{context => <Component {...props} routeManager={context} />}
|
||||
</RouteManagerContext.Consumer>
|
||||
)
|
||||
}
|
||||
|
||||
export const StackManager = withContext(StackManagerInner);
|
||||
|
Reference in New Issue
Block a user