fix(react): fix regression with history.replace in new react router (#21698)

This commit is contained in:
Ely Lucas 2020-07-08 10:22:08 -06:00 committed by GitHub
parent c171ccbd37
commit 81ef3f1ecd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 29 deletions

View File

@ -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
const lastRoute = this.locationHistory.getCurrentRouteInfoForTab(routeInfo.tab);
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);

View File

@ -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')
})
})

View File

@ -47,6 +47,20 @@ Cypress.Commands.add('ionPageVisible', (pageId) => {
// 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) => {
cy.contains(element, contains).click();
cy.wait(250);
@ -77,7 +91,7 @@ Cypress.Commands.add('ionMenuNav', (contains) => {
Cypress.Commands.add('ionTabClick', (tabText) => {
// TODO: figure out how to get rid of this wait. Switching tabs after a forward nav to a details page needs it
cy.wait(250)
cy.contains('ion-tab-button', tabText).click({ force: true})
cy.contains('ion-tab-button', tabText).click({ force: true })
// cy.get('ion-tab-button.tab-selected').contains(tabText)
});

View File

@ -31,6 +31,7 @@ import MultipleTabs from './pages/muiltiple-tabs/MultipleTabs';
import DynamicTabs from './pages/dynamic-tabs/DynamicTabs';
import NestedOutlet from './pages/nested-outlet/NestedOutlet';
import NestedOutlet2 from './pages/nested-outlet/NestedOutlet2';
import ReplaceAction from './pages/replace-action/Replace';
debugger;
const App: React.FC = () => {
return (
@ -44,6 +45,7 @@ const App: React.FC = () => {
<Route path="/dynamic-tabs" component={DynamicTabs} />
<Route path="/nested-outlet" component={NestedOutlet} />
<Route path="/nested-outlet2" component={NestedOutlet2} />
<Route path="/replace-action" component={ReplaceAction} />
</IonReactRouter>
</IonApp>

View File

@ -32,10 +32,13 @@ const Main: React.FC<MainProps> = () => {
<IonItem routerLink="/nested-outlet2">
<IonLabel>Nested Outlet 2</IonLabel>
</IonItem>
<IonItem routerLink="/replace-action">
<IonLabel>Replace Action</IonLabel>
</IonItem>
</IonList>
</IonContent>
</IonPage>
);
};
export default Main;
export default Main;

View File

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

View File

@ -6,7 +6,6 @@ import Tabs from './Tabs';
import Favorites from './Favorites';
import OtherPage from './OtherPage';
import PropsTest from './PropsTest';
import TopPage from './TopPage';
interface RoutingProps {
}
@ -36,7 +35,6 @@ const Routing: React.FC<RoutingProps> = () => {
}} /> */}
<Route path="/routing/otherpage" component={OtherPage} />
<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={() => <Redirect to="/tabs" />} /> */}
@ -45,4 +43,4 @@ const Routing: React.FC<RoutingProps> = () => {
);
};
export default Routing;
export default Routing;

View File

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