fix(react): support navigating to same page and route updates in IonRouterOutlet, fixes #19891, #19892, #19986

This commit is contained in:
Ely Lucas
2019-12-03 14:22:26 -07:00
committed by GitHub
parent eef55bb007
commit f9bf8dbe6f
9 changed files with 180 additions and 90 deletions

View File

@ -3,7 +3,6 @@ import { NavContext, NavContextState } from '@ionic/react';
import { Location as HistoryLocation, UnregisterCallback } from 'history'; import { Location as HistoryLocation, UnregisterCallback } from 'history';
import React from 'react'; import React from 'react';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
import { StackManager } from './StackManager'; import { StackManager } from './StackManager';
interface NavManagerProps extends RouteComponentProps { interface NavManagerProps extends RouteComponentProps {
@ -25,7 +24,6 @@ export class NavManager extends React.Component<NavManagerProps, NavContextState
getPageManager: this.getPageManager.bind(this), getPageManager: this.getPageManager.bind(this),
currentPath: this.props.location.pathname, currentPath: this.props.location.pathname,
registerIonPage: () => { return; }, // overridden in View for each IonPage registerIonPage: () => { return; }, // overridden in View for each IonPage
tabNavigate: this.tabNavigate.bind(this)
}; };
this.listenUnregisterCallback = this.props.history.listen((location: HistoryLocation) => { this.listenUnregisterCallback = this.props.history.listen((location: HistoryLocation) => {
@ -53,12 +51,8 @@ export class NavManager extends React.Component<NavManagerProps, NavContextState
this.props.onNavigateBack(defaultHref); this.props.onNavigateBack(defaultHref);
} }
navigate(path: string, direction?: RouterDirection | 'none') { navigate(path: string, direction?: RouterDirection | 'none', type: 'push' | 'replace' = 'push') {
this.props.onNavigate('push', path, direction); this.props.onNavigate(type, path, direction);
}
tabNavigate(path: string) {
this.props.onNavigate('replace', path, 'back');
} }
getPageManager() { getPageManager() {

View File

@ -4,18 +4,22 @@ import { ViewStacks } from './ViewStacks';
export interface RouteManagerContextState { export interface RouteManagerContextState {
syncView: (page: HTMLElement, viewId: string) => void; syncView: (page: HTMLElement, viewId: string) => void;
syncRoute: (id: string, route: any) => void;
hideView: (viewId: string) => void; hideView: (viewId: string) => void;
viewStacks: ViewStacks; viewStacks: ViewStacks;
setupIonRouter: (id: string, children: ReactNode, routerOutlet: HTMLIonRouterOutletElement) => void; setupIonRouter: (id: string, children: ReactNode, routerOutlet: HTMLIonRouterOutletElement) => void;
removeViewStack: (stack: string) => void; removeViewStack: (stack: string) => void;
getRoute: (id: string) => any;
} }
export const RouteManagerContext = /*@__PURE__*/React.createContext<RouteManagerContextState>({ export const RouteManagerContext = /*@__PURE__*/React.createContext<RouteManagerContextState>({
viewStacks: new ViewStacks(), viewStacks: new ViewStacks(),
syncView: () => { navContextNotFoundError(); }, syncView: () => { navContextNotFoundError(); },
syncRoute: () => { navContextNotFoundError(); },
hideView: () => { navContextNotFoundError(); }, hideView: () => { navContextNotFoundError(); },
setupIonRouter: () => Promise.reject(navContextNotFoundError()), setupIonRouter: () => Promise.reject(navContextNotFoundError()),
removeViewStack: () => { navContextNotFoundError(); } removeViewStack: () => { navContextNotFoundError(); },
getRoute: () => { navContextNotFoundError(); }
}); });
function navContextNotFoundError() { function navContextNotFoundError() {

View File

@ -2,7 +2,7 @@ import { NavDirection } from '@ionic/core';
import { RouterDirection, getConfig } from '@ionic/react'; import { RouterDirection, getConfig } from '@ionic/react';
import { Action as HistoryAction, Location as HistoryLocation, UnregisterCallback } from 'history'; import { Action as HistoryAction, Location as HistoryLocation, UnregisterCallback } from 'history';
import React from 'react'; import React from 'react';
import { RouteComponentProps, matchPath, withRouter } from 'react-router-dom'; import { RouteComponentProps, withRouter, matchPath } from 'react-router-dom';
import { generateId, isDevMode } from '../utils'; import { generateId, isDevMode } from '../utils';
import { LocationHistory } from '../utils/LocationHistory'; import { LocationHistory } from '../utils/LocationHistory';
@ -23,6 +23,7 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
activeIonPageId?: string; activeIonPageId?: string;
currentDirection?: RouterDirection; currentDirection?: RouterDirection;
locationHistory = new LocationHistory(); locationHistory = new LocationHistory();
routes: { [key: string]: any } = {};
constructor(props: RouteComponentProps) { constructor(props: RouteComponentProps) {
super(props); super(props);
@ -34,7 +35,9 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
hideView: this.hideView.bind(this), hideView: this.hideView.bind(this),
setupIonRouter: this.setupIonRouter.bind(this), setupIonRouter: this.setupIonRouter.bind(this),
removeViewStack: this.removeViewStack.bind(this), removeViewStack: this.removeViewStack.bind(this),
syncView: this.syncView.bind(this) syncView: this.syncView.bind(this),
syncRoute: this.syncRoute.bind(this),
getRoute: this.getRoute.bind(this)
}; };
this.locationHistory.add({ this.locationHistory.add({
@ -46,6 +49,10 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
}); });
} }
// componentDidMount() {
// this.setActiveView(this.props.location, this.state.action!);
// }
componentDidUpdate(_prevProps: RouteComponentProps, prevState: RouteManagerState) { componentDidUpdate(_prevProps: RouteComponentProps, prevState: RouteManagerState) {
// Trigger a page change if the location or action is different // Trigger a page change if the location or action is different
if (this.state.location && prevState.location !== this.state.location || prevState.action !== this.state.action) { if (this.state.location && prevState.location !== this.state.location || prevState.action !== this.state.action) {
@ -59,6 +66,10 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
} }
} }
getRoute(id: string) {
return this.routes[id];
}
hideView(viewId: string) { hideView(viewId: string) {
const viewStacks = Object.assign(new ViewStacks(), this.state.viewStacks); const viewStacks = Object.assign(new ViewStacks(), this.state.viewStacks);
const { view } = viewStacks.findViewInfoById(viewId); const { view } = viewStacks.findViewInfoById(viewId);
@ -95,18 +106,22 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
let direction: RouterDirection | undefined = (location.state && location.state.direction) || 'forward'; let direction: RouterDirection | undefined = (location.state && location.state.direction) || 'forward';
let leavingView: ViewItem | undefined; let leavingView: ViewItem | undefined;
const viewStackKeys = viewStacks.getKeys(); const viewStackKeys = viewStacks.getKeys();
let shouldTransitionPage = false;
let leavingViewHtml: string | undefined;
viewStackKeys.forEach(key => { viewStackKeys.forEach(key => {
const { view: enteringView, viewStack: enteringViewStack, match } = viewStacks.findViewInfoByLocation(location, key); const { view: enteringView, viewStack: enteringViewStack, match } = viewStacks.findViewInfoByLocation(location, key);
if (!enteringView || !enteringViewStack) { if (!enteringView || !enteringViewStack) {
return; return;
} }
leavingView = viewStacks.findViewInfoById(this.activeIonPageId).view; leavingView = viewStacks.findViewInfoById(this.activeIonPageId).view;
if (enteringView.isIonRoute) { if (enteringView.isIonRoute) {
enteringView.show = true; enteringView.show = true;
enteringView.mount = true; enteringView.mount = true;
enteringView.routeData.match = match!; enteringView.routeData.match = match!;
shouldTransitionPage = true;
this.activeIonPageId = enteringView.id; this.activeIonPageId = enteringView.id;
@ -129,10 +144,12 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
leavingView.mount = false; leavingView.mount = false;
this.removeOrphanedViews(enteringView, enteringViewStack); this.removeOrphanedViews(enteringView, enteringViewStack);
} }
leavingViewHtml = enteringView.id === leavingView.id ? leavingView.ionPageElement!.outerHTML : undefined;
} else { } else {
// If there is not a leavingView, then we shouldn't provide a direction // If there is not a leavingView, then we shouldn't provide a direction
direction = undefined; direction = undefined;
} }
} else { } else {
enteringView.show = true; enteringView.show = true;
enteringView.mount = true; enteringView.mount = true;
@ -151,6 +168,7 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
this.setState({ this.setState({
viewStacks viewStacks
}, () => { }, () => {
if (shouldTransitionPage) {
const { view: enteringView, viewStack } = this.state.viewStacks.findViewInfoById(this.activeIonPageId); const { view: enteringView, viewStack } = this.state.viewStacks.findViewInfoById(this.activeIonPageId);
if (enteringView && viewStack) { if (enteringView && viewStack) {
const enteringEl = enteringView.ionPageElement ? enteringView.ionPageElement : undefined; const enteringEl = enteringView.ionPageElement ? enteringView.ionPageElement : undefined;
@ -164,15 +182,17 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
leavingEl!, leavingEl!,
viewStack.routerOutlet, viewStack.routerOutlet,
navDirection, navDirection,
shouldGoBack); shouldGoBack,
leavingViewHtml);
} else if (leavingEl) { } else if (leavingEl) {
leavingEl.classList.add('ion-page-hidden'); leavingEl.classList.add('ion-page-hidden');
leavingEl.setAttribute('aria-hidden', 'true'); leavingEl.setAttribute('aria-hidden', 'true');
} }
}
// Warn if an IonPage was not eventually rendered in Dev Mode // Warn if an IonPage was not eventually rendered in Dev Mode
if (isDevMode()) { if (isDevMode()) {
if (enteringView.routeData.match!.url !== location.pathname) { if (enteringView && enteringView.routeData.match!.url !== location.pathname) {
setTimeout(() => { setTimeout(() => {
const { view } = this.state.viewStacks.findViewInfoById(this.activeIonPageId); const { view } = this.state.viewStacks.findViewInfoById(this.activeIonPageId);
if (view!.routeData.match!.url !== location.pathname) { if (view!.routeData.match!.url !== location.pathname) {
@ -212,15 +232,18 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
let activeId: string | undefined; let activeId: string | undefined;
const ionRouterOutlet = React.Children.only(children) as React.ReactElement; const ionRouterOutlet = React.Children.only(children) as React.ReactElement;
React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => { React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
views.push(createViewItem(child, this.props.history.location)); const routeId = generateId();
this.routes[routeId] = child;
views.push(createViewItem(child, routeId, this.props.history.location));
}); });
this.registerViewStack(id, activeId, views, routerOutlet, this.props.location); this.registerViewStack(id, activeId, views, routerOutlet, this.props.location);
function createViewItem(child: React.ReactElement<any>, location: HistoryLocation) { function createViewItem(child: React.ReactElement<any>, routeId: string, location: HistoryLocation) {
const viewId = generateId(); const viewId = generateId();
const key = generateId(); const key = generateId();
const route = child;
// const route = child;
const matchProps = { const matchProps = {
exact: child.props.exact, exact: child.props.exact,
path: child.props.path || child.props.from, path: child.props.path || child.props.from,
@ -234,7 +257,7 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
match, match,
childProps: child.props childProps: child.props
}, },
route, routeId,
mount: true, mount: true,
show: !!match, show: !!match,
isIonRoute: false isIonRoute: false
@ -326,19 +349,43 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
}); });
} }
private async commitView(enteringEl: HTMLElement, leavingEl: HTMLElement, ionRouterOuter: HTMLIonRouterOutletElement, direction?: NavDirection, showGoBack?: boolean) { syncRoute(_id: string, routerOutlet: any) {
const ionRouterOutlet = React.Children.only(routerOutlet) as React.ReactElement;
if (enteringEl === leavingEl) { React.Children.forEach(ionRouterOutlet.props.children, (child: React.ReactElement) => {
return; for (let routeKey in this.routes) {
const route = this.routes[routeKey];
if (route.props.path == child.props.path) {
this.routes[routeKey] = child;
}
}
});
} }
await ionRouterOuter.commit(enteringEl, leavingEl, { private async commitView(enteringEl: HTMLElement, leavingEl: HTMLElement, ionRouterOutlet: HTMLIonRouterOutletElement, direction?: NavDirection, showGoBack?: boolean, leavingViewHtml?: string) {
if ((enteringEl === leavingEl) && direction && leavingViewHtml) {
// If a page is transitioning to another version of itself
// we clone it so we can have an animation to show
const newLeavingElement = clonePageElement(leavingViewHtml);
ionRouterOutlet.appendChild(newLeavingElement);
await ionRouterOutlet.commit(enteringEl, newLeavingElement, {
deepWait: true, deepWait: true,
duration: direction === undefined ? 0 : undefined, duration: direction === undefined ? 0 : undefined,
direction, direction,
showGoBack, showGoBack,
progressAnimation: false progressAnimation: false
}); });
ionRouterOutlet.removeChild(newLeavingElement);
} else {
await ionRouterOutlet.commit(enteringEl, leavingEl, {
deepWait: true,
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation: false
});
}
if (leavingEl && (enteringEl !== leavingEl)) { if (leavingEl && (enteringEl !== leavingEl)) {
/** add hidden attributes */ /** add hidden attributes */
@ -357,9 +404,17 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
} }
navigateBack(defaultHref?: string) { navigateBack(defaultHref?: string) {
const { view: activeIonPage } = this.state.viewStacks.findViewInfoById(this.activeIonPageId); const { view: leavingView } = this.state.viewStacks.findViewInfoById(this.activeIonPageId);
if (activeIonPage) { if (leavingView) {
const { view: enteringView } = this.state.viewStacks.findViewInfoById(activeIonPage.prevId); if (leavingView.id === leavingView.prevId) {
const previousLocation = this.locationHistory.previous();
if(previousLocation) {
this.handleNavigate('replace', previousLocation.pathname + previousLocation.search, 'back');
} else {
defaultHref && this.handleNavigate('replace', defaultHref, 'back');
}
} else {
const { view: enteringView } = this.state.viewStacks.findViewInfoById(leavingView.prevId);
if (enteringView) { if (enteringView) {
const lastLocation = this.locationHistory.findLastLocationByUrl(enteringView.routeData.match!.url); const lastLocation = this.locationHistory.findLastLocationByUrl(enteringView.routeData.match!.url);
if (lastLocation) { if (lastLocation) {
@ -377,6 +432,7 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
} }
} }
} }
}
} else { } else {
if (defaultHref) { if (defaultHref) {
this.handleNavigate('replace', defaultHref, 'back'); this.handleNavigate('replace', defaultHref, 'back');
@ -399,5 +455,18 @@ class RouteManager extends React.Component<RouteComponentProps, RouteManagerStat
} }
} }
function clonePageElement(leavingViewHtml: string) {
const newEl = document.createElement('div');
newEl.innerHTML = leavingViewHtml;
newEl.classList.add('ion-page-hidden');
newEl.style.zIndex = null;
// Remove an existing back button so the new element doesn't get two of them
const ionBackButton = newEl.getElementsByTagName('ion-back-button');
if (ionBackButton[0]) {
ionBackButton[0].innerHTML = '';
}
return newEl.firstChild as HTMLElement;
}
export const RouteManagerWithRouter = withRouter(RouteManager); export const RouteManagerWithRouter = withRouter(RouteManager);
RouteManagerWithRouter.displayName = 'RouteManager'; RouteManagerWithRouter.displayName = 'RouteManager';

View File

@ -2,22 +2,24 @@ import React from 'react';
import { generateId, isDevMode } from '../utils'; import { generateId, isDevMode } from '../utils';
import { RouteManagerContext } from './RouteManagerContext'; import { RouteManagerContext, RouteManagerContextState } from './RouteManagerContext';
import { View } from './View'; import { View } from './View';
import { ViewItem } from './ViewItem'; import { ViewItem } from './ViewItem';
import { ViewTransitionManager } from './ViewTransitionManager'; import { ViewTransitionManager } from './ViewTransitionManager';
interface StackManagerProps { interface StackManagerProps {
id?: string; id?: string;
routeManager: RouteManagerContextState;
children?: React.ReactNode;
} }
interface StackManagerState { interface StackManagerState {
routerOutletReady: boolean; routerOutletReady: boolean;
} }
export class StackManager extends React.Component<StackManagerProps, StackManagerState> { class StackManagerInner extends React.Component<StackManagerProps, StackManagerState> {
routerOutletEl: React.RefObject<HTMLIonRouterOutletElement> = React.createRef(); routerOutletEl: React.RefObject<HTMLIonRouterOutletElement> = React.createRef();
context!: React.ContextType<typeof RouteManagerContext>;
id: string; id: string;
constructor(props: StackManagerProps) { constructor(props: StackManagerProps) {
@ -31,7 +33,7 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
} }
componentDidMount() { 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.routerOutletEl.current!.addEventListener('routerOutletReady', () => {
this.setState({ this.setState({
routerOutletReady: true 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() { componentWillUnmount() {
this.context.removeViewStack(this.id); this.props.routeManager.removeViewStack(this.id);
} }
handleViewSync(page: HTMLElement, viewId: string) { handleViewSync(page: HTMLElement, viewId: string) {
this.context.syncView(page, viewId); this.props.routeManager.syncView(page, viewId);
} }
handleHideView(viewId: string) { handleHideView(viewId: string) {
this.context.hideView(viewId); this.props.routeManager.hideView(viewId);
} }
renderChild(item: ViewItem) { renderChild(item: ViewItem, route: any) {
const component = React.cloneElement(item.route, { const component = React.cloneElement(route, {
computedMatch: item.routeData.match computedMatch: item.routeData.match
}); });
return component; return component;
} }
render() { render() {
const context = this.context; const routeManager = this.props.routeManager;
const viewStack = context.viewStacks.get(this.id); const viewStack = routeManager.viewStacks.get(this.id);
const views = (viewStack || { views: [] }).views.filter(x => x.show); const views = (viewStack || { views: [] }).views.filter(x => x.show);
const ionRouterOutlet = React.Children.only(this.props.children) as React.ReactElement; const ionRouterOutlet = React.Children.only(this.props.children) as React.ReactElement;
const { routerOutletReady } = this.state; const { routerOutletReady } = this.state;
const childElements = routerOutletReady ? views.map(view => { const childElements = routerOutletReady ? views.map(view => {
const route = routeManager.getRoute(view.routeId);
return ( return (
<ViewTransitionManager <ViewTransitionManager
id={view.id} id={view.id}
@ -76,8 +84,9 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
onViewSync={this.handleViewSync} onViewSync={this.handleViewSync}
onHideView={this.handleHideView} onHideView={this.handleHideView}
view={view} view={view}
route={route}
> >
{this.renderChild(view)} {this.renderChild(view, route)}
</View> </View>
</ViewTransitionManager> </ViewTransitionManager>
); );
@ -99,8 +108,14 @@ export class StackManager extends React.Component<StackManagerProps, StackManage
return routerOutletChild; return routerOutletChild;
} }
}
static get contextType() { const withContext = (Component: any) => {
return RouteManagerContext; return (props: any) => (
} <RouteManagerContext.Consumer>
{context => <Component {...props} routeManager={context} />}
</RouteManagerContext.Consumer>
)
} }
export const StackManager = withContext(StackManagerInner);

View File

@ -10,6 +10,7 @@ interface ViewProps extends React.HTMLAttributes<HTMLElement> {
onViewSync: (page: HTMLElement, viewId: string) => void; onViewSync: (page: HTMLElement, viewId: string) => void;
onHideView: (viewId: string) => void; onHideView: (viewId: string) => void;
view: ViewItem; view: ViewItem;
route: any;
} }
/** /**
@ -23,11 +24,11 @@ export class View extends React.Component<ViewProps, {}> {
/** /**
* If we can tell if view is a redirect, hide it so it will work again in future * If we can tell if view is a redirect, hide it so it will work again in future
*/ */
const { view } = this.props; const { view, route } = this.props;
if (view.route.type === Redirect) { if (route.type === Redirect) {
this.props.onHideView(view.id); this.props.onHideView(view.id);
} else if (view.route.type === Route && view.route.props.render) { } else if (route.type === Route && route.props.render) {
if (view.route.props.render().type === Redirect) { if (route.props.render().type === Redirect) {
this.props.onHideView(view.id); this.props.onHideView(view.id);
} }
} }

View File

@ -3,8 +3,10 @@ export interface ViewItem<RouteData = any> {
id: string; id: string;
/** The key used by React. A new key is generated each time the view comes into the DOM so React thinks its a completely new element. */ /** The key used by React. A new key is generated each time the view comes into the DOM so React thinks its a completely new element. */
key: string; key: string;
routeId: string;
/** The <Route /> or <Redirect /> component associated with the view */ /** The <Route /> or <Redirect /> component associated with the view */
route: React.ReactElement<any>; // route: React.ReactElement<any>;
/** The reference to the <IonPage /> element. */ /** The reference to the <IonPage /> element. */
ionPageElement?: HTMLElement; ionPageElement?: HTMLElement;
/** The routeData for the view. */ /** The routeData for the view. */
@ -23,4 +25,9 @@ export interface ViewItem<RouteData = any> {
* An IonRoute is a Route that contains an IonPage. Only IonPages participate in transition and lifecycle events. * An IonRoute is a Route that contains an IonPage. Only IonPages participate in transition and lifecycle events.
*/ */
isIonRoute: boolean; isIonRoute: boolean;
/**
* location of the view
*/
location?: string;
} }

View File

@ -58,10 +58,11 @@ export class ViewStacks {
path: v.routeData.childProps.path || v.routeData.childProps.from, path: v.routeData.childProps.path || v.routeData.childProps.from,
component: v.routeData.childProps.component component: v.routeData.childProps.component
}; };
match = matchPath(location.pathname, matchProps); const myMatch: IonRouteData['match'] | null | undefined = matchPath(location.pathname, matchProps);
if (match) { if (myMatch) {
view = v; view = v;
return true; match = myMatch;
return view.location === location.pathname;
} }
return false; return false;
} }

View File

@ -69,12 +69,13 @@ const IonTabBarUnwrapped = /*@__PURE__*/(() => class extends React.Component<Pro
} }
private onTabButtonClick = (e: CustomEvent<{ href: string, selected: boolean, tab: string }>) => { private onTabButtonClick = (e: CustomEvent<{ href: string, selected: boolean, tab: string }>) => {
if (this.state.activeTab === e.detail.tab) {
const originalHref = this.state.tabs[e.detail.tab].originalHref; const originalHref = this.state.tabs[e.detail.tab].originalHref;
if (this.context.hasIonicRouter()) { const currentHref = this.state.tabs[e.detail.tab].currentHref;
this.context.tabNavigate(originalHref); if (this.state.activeTab === e.detail.tab) {
if (originalHref === currentHref) {
this.context.navigate(originalHref, 'none');
} else { } else {
this.context.navigate(originalHref, 'back'); this.context.navigate(originalHref, 'back', 'replace');
} }
} else { } else {
if (this.props.onIonTabsWillChange) { if (this.props.onIonTabsWillChange) {
@ -83,7 +84,7 @@ const IonTabBarUnwrapped = /*@__PURE__*/(() => class extends React.Component<Pro
if (this.props.onIonTabsDidChange) { if (this.props.onIonTabsDidChange) {
this.props.onIonTabsDidChange(new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } })); this.props.onIonTabsDidChange(new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } }));
} }
this.context.navigate(this.state.tabs[e.detail.tab].currentHref, 'none'); this.context.navigate(currentHref, 'none');
} }
} }

View File

@ -5,10 +5,9 @@ export interface NavContextState {
getPageManager: () => any; getPageManager: () => any;
getStackManager: () => any; getStackManager: () => any;
goBack: (defaultHref?: string) => void; goBack: (defaultHref?: string) => void;
navigate: (path: string, direction?: RouterDirection | 'none') => void; navigate: (path: string, direction?: RouterDirection | 'none', type?: 'push' | 'replace') => void;
hasIonicRouter: () => boolean; hasIonicRouter: () => boolean;
registerIonPage: (page: HTMLElement) => void; registerIonPage: (page: HTMLElement) => void;
tabNavigate: (url: string) => void;
currentPath: string | undefined; currentPath: string | undefined;
} }
@ -23,7 +22,6 @@ export const NavContext = /*@__PURE__*/React.createContext<NavContextState>({
} }
}, },
navigate: (path: string) => { window.location.pathname = path; }, navigate: (path: string) => { window.location.pathname = path; },
tabNavigate: () => undefined,
hasIonicRouter: () => false, hasIonicRouter: () => false,
registerIonPage: () => undefined, registerIonPage: () => undefined,
currentPath: undefined currentPath: undefined