mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 01:03:03 +08:00
fix(react): fix regression with history.replace in new react router (#21698)
This commit is contained in:
@ -166,6 +166,13 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
|||||||
// If we are switching tabs grab the last route info for the tab and use its pushedByRoute
|
// If we are switching tabs grab the last route info for the tab and use its pushedByRoute
|
||||||
const lastRoute = this.locationHistory.getCurrentRouteInfoForTab(routeInfo.tab);
|
const lastRoute = this.locationHistory.getCurrentRouteInfoForTab(routeInfo.tab);
|
||||||
routeInfo.pushedByRoute = lastRoute?.pushedByRoute;
|
routeInfo.pushedByRoute = lastRoute?.pushedByRoute;
|
||||||
|
} else if (routeInfo.routeAction === 'replace') {
|
||||||
|
// Make sure to set the lastPathname, etc.. to the current route so the page transitions out
|
||||||
|
const currentRouteInfo = this.locationHistory.current();
|
||||||
|
routeInfo.lastPathname = currentRouteInfo?.pathname || routeInfo.lastPathname;
|
||||||
|
routeInfo.pushedByRoute = currentRouteInfo?.pushedByRoute || routeInfo.pushedByRoute;
|
||||||
|
routeInfo.routeDirection = currentRouteInfo?.routeDirection || routeInfo.routeDirection;
|
||||||
|
routeInfo.routeAnimation = currentRouteInfo?.routeAnimation || routeInfo.routeAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.locationHistory.add(routeInfo);
|
this.locationHistory.add(routeInfo);
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
describe('Replace Action', () => {
|
||||||
|
|
||||||
|
/*
|
||||||
|
This spec tests that when a 'replace' action is used, that it does replace the current
|
||||||
|
history item in location history.
|
||||||
|
*/
|
||||||
|
|
||||||
|
it('/replace-action > Goto Page2 > Goto Page3 > Browser Back > Page1 should be visible and Page2 should be gone', () => {
|
||||||
|
cy.visit(`http://localhost:${port}/replace-action`)
|
||||||
|
cy.ionPageVisible('page1')
|
||||||
|
cy.ionNav('ion-button', 'Goto Page2')
|
||||||
|
cy.ionPageVisible('page2')
|
||||||
|
cy.ionNav('ion-button', 'Goto Page3')
|
||||||
|
cy.ionPageVisible('page3')
|
||||||
|
cy.go('back')
|
||||||
|
cy.ionPageVisible('page1')
|
||||||
|
cy.ionPageDoesNotExist('page2')
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
})
|
@ -47,6 +47,20 @@ Cypress.Commands.add('ionPageVisible', (pageId) => {
|
|||||||
// cy.get(`div.ion-page[data-pageid=${pageId}]`).should('have.attr', 'style', 'z-index: 101;')
|
// cy.get(`div.ion-page[data-pageid=${pageId}]`).should('have.attr', 'style', 'z-index: 101;')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
Cypress.Commands.add('ionPageHidden', (pageId) => {
|
||||||
|
cy.get(`div.ion-page[data-pageid=${pageId}]`)
|
||||||
|
.should('have.class', 'ion-page-hidden')
|
||||||
|
.should('have.class', 'ion-page-invisible')
|
||||||
|
.should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('ionPageDoesNotExist', (pageId) => {
|
||||||
|
cy.get(`div.ion-page[data-pageid=${pageId}]`)
|
||||||
|
.should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
Cypress.Commands.add('ionNav', (element, contains) => {
|
Cypress.Commands.add('ionNav', (element, contains) => {
|
||||||
cy.contains(element, contains).click();
|
cy.contains(element, contains).click();
|
||||||
cy.wait(250);
|
cy.wait(250);
|
||||||
|
@ -31,6 +31,7 @@ import MultipleTabs from './pages/muiltiple-tabs/MultipleTabs';
|
|||||||
import DynamicTabs from './pages/dynamic-tabs/DynamicTabs';
|
import DynamicTabs from './pages/dynamic-tabs/DynamicTabs';
|
||||||
import NestedOutlet from './pages/nested-outlet/NestedOutlet';
|
import NestedOutlet from './pages/nested-outlet/NestedOutlet';
|
||||||
import NestedOutlet2 from './pages/nested-outlet/NestedOutlet2';
|
import NestedOutlet2 from './pages/nested-outlet/NestedOutlet2';
|
||||||
|
import ReplaceAction from './pages/replace-action/Replace';
|
||||||
debugger;
|
debugger;
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -44,6 +45,7 @@ const App: React.FC = () => {
|
|||||||
<Route path="/dynamic-tabs" component={DynamicTabs} />
|
<Route path="/dynamic-tabs" component={DynamicTabs} />
|
||||||
<Route path="/nested-outlet" component={NestedOutlet} />
|
<Route path="/nested-outlet" component={NestedOutlet} />
|
||||||
<Route path="/nested-outlet2" component={NestedOutlet2} />
|
<Route path="/nested-outlet2" component={NestedOutlet2} />
|
||||||
|
<Route path="/replace-action" component={ReplaceAction} />
|
||||||
|
|
||||||
</IonReactRouter>
|
</IonReactRouter>
|
||||||
</IonApp>
|
</IonApp>
|
||||||
|
@ -32,6 +32,9 @@ const Main: React.FC<MainProps> = () => {
|
|||||||
<IonItem routerLink="/nested-outlet2">
|
<IonItem routerLink="/nested-outlet2">
|
||||||
<IonLabel>Nested Outlet 2</IonLabel>
|
<IonLabel>Nested Outlet 2</IonLabel>
|
||||||
</IonItem>
|
</IonItem>
|
||||||
|
<IonItem routerLink="/replace-action">
|
||||||
|
<IonLabel>Replace Action</IonLabel>
|
||||||
|
</IonItem>
|
||||||
</IonList>
|
</IonList>
|
||||||
</IonContent>
|
</IonContent>
|
||||||
</IonPage>
|
</IonPage>
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonButton, IonRouterOutlet, IonButtons, IonBackButton } from '@ionic/react';
|
||||||
|
import { Route, Redirect, useHistory } from 'react-router';
|
||||||
|
|
||||||
|
interface TopPageProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
const ReplaceAction: React.FC<TopPageProps> = () => {
|
||||||
|
return (
|
||||||
|
<IonRouterOutlet>
|
||||||
|
<Route path="/replace-action/page1" component={Page1} exact />
|
||||||
|
<Route path="/replace-action/page2" component={Page2} exact />
|
||||||
|
<Route path="/replace-action/page3" component={Edit} exact />
|
||||||
|
<Route exact path="/replace-action" render={() => <Redirect to="/replace-action/page1" />} />
|
||||||
|
</IonRouterOutlet>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Page1: React.FC = () => (
|
||||||
|
<IonPage data-pageid="page1">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonButtons slot="start">
|
||||||
|
<IonBackButton />
|
||||||
|
</IonButtons>
|
||||||
|
<IonTitle>Page one</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton routerLink={'/replace-action/page2'}>
|
||||||
|
Goto Page2
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Page2: React.FC = () => {
|
||||||
|
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
const clickButton = () => {
|
||||||
|
history.replace('/replace-action/page3');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="page2">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonButtons slot="start">
|
||||||
|
<IonBackButton/>
|
||||||
|
</IonButtons>
|
||||||
|
<IonTitle>Page two</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton onClick={() => clickButton()}>
|
||||||
|
Goto Page3
|
||||||
|
</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Edit: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="page3">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonButtons slot="start">
|
||||||
|
<IonBackButton defaultHref="/replace-action/page1"/>
|
||||||
|
</IonButtons>
|
||||||
|
<IonTitle>Page three</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<p>Page 3</p>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReplaceAction;
|
@ -6,7 +6,6 @@ import Tabs from './Tabs';
|
|||||||
import Favorites from './Favorites';
|
import Favorites from './Favorites';
|
||||||
import OtherPage from './OtherPage';
|
import OtherPage from './OtherPage';
|
||||||
import PropsTest from './PropsTest';
|
import PropsTest from './PropsTest';
|
||||||
import TopPage from './TopPage';
|
|
||||||
|
|
||||||
interface RoutingProps {
|
interface RoutingProps {
|
||||||
}
|
}
|
||||||
@ -36,7 +35,6 @@ const Routing: React.FC<RoutingProps> = () => {
|
|||||||
}} /> */}
|
}} /> */}
|
||||||
<Route path="/routing/otherpage" component={OtherPage} />
|
<Route path="/routing/otherpage" component={OtherPage} />
|
||||||
<Route path="/routing/propstest" component={PropsTest} />
|
<Route path="/routing/propstest" component={PropsTest} />
|
||||||
<Route path="/routing/toppage" component={TopPage} />
|
|
||||||
<Route render={() => <IonPage data-pageid="not-found"><IonContent><div>Not found</div></IonContent></IonPage>} />
|
<Route render={() => <IonPage data-pageid="not-found"><IonContent><div>Not found</div></IonContent></IonPage>} />
|
||||||
{/* <Route render={() => <Redirect to="/tabs" />} /> */}
|
{/* <Route render={() => <Redirect to="/tabs" />} /> */}
|
||||||
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonButton } from '@ionic/react';
|
|
||||||
|
|
||||||
interface TopPageProps {
|
|
||||||
}
|
|
||||||
|
|
||||||
const TopPage: React.FC<TopPageProps> = () => {
|
|
||||||
return (
|
|
||||||
<IonPage data-pageid="toppage">
|
|
||||||
<IonHeader>
|
|
||||||
<IonToolbar>
|
|
||||||
<IonTitle>TopPage</IonTitle>
|
|
||||||
</IonToolbar>
|
|
||||||
</IonHeader>
|
|
||||||
<IonContent>
|
|
||||||
<IonButton routerLink="/otherpage">
|
|
||||||
Go to Other Page
|
|
||||||
</IonButton>
|
|
||||||
</IonContent>
|
|
||||||
</IonPage>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TopPage;
|
|
Reference in New Issue
Block a user