mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(react-router): remove page transition flicker on outlet mounting (#24667)
Resolves #24666
This commit is contained in:
@@ -9,6 +9,14 @@ export class IonRouteInner extends React.PureComponent<IonRouteProps> {
|
||||
path={this.props.path}
|
||||
exact={this.props.exact}
|
||||
render={this.props.render}
|
||||
/**
|
||||
* `computedMatch` is a private API in react-router v5 that
|
||||
* has been removed in v6.
|
||||
*
|
||||
* This needs to be removed when we support v6.
|
||||
*
|
||||
* TODO: FW-647
|
||||
*/
|
||||
computedMatch={(this.props as any).computedMatch}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -29,6 +29,8 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
isInOutlet: () => true,
|
||||
};
|
||||
|
||||
private pendingPageTransition = false;
|
||||
|
||||
constructor(props: StackManagerProps) {
|
||||
super(props);
|
||||
this.registerIonPage = this.registerIonPage.bind(this);
|
||||
@@ -46,8 +48,9 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: StackManagerProps) {
|
||||
if (this.props.routeInfo.pathname !== prevProps.routeInfo.pathname) {
|
||||
if (this.props.routeInfo.pathname !== prevProps.routeInfo.pathname || this.pendingPageTransition) {
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
this.pendingPageTransition = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +60,15 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
}
|
||||
|
||||
async handlePageTransition(routeInfo: RouteInfo) {
|
||||
// If routerOutlet isn't quite ready, give it another try in a moment
|
||||
if (!this.routerOutletElement || !this.routerOutletElement.commit) {
|
||||
setTimeout(() => this.handlePageTransition(routeInfo), 10);
|
||||
/**
|
||||
* The route outlet has not mounted yet. We need to wait for it to render
|
||||
* before we can transition the page.
|
||||
*
|
||||
* Set a flag to indicate that we should transition the page after
|
||||
* the component has updated.
|
||||
*/
|
||||
this.pendingPageTransition = true;
|
||||
} else {
|
||||
let enteringViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
let leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id);
|
||||
|
||||
@@ -99,7 +99,7 @@ export const IonTabs = /*@__PURE__*/ (() =>
|
||||
return;
|
||||
}
|
||||
if (child.type === IonRouterOutlet || child.type.isRouterOutlet) {
|
||||
outlet = React.cloneElement(child, { tabs: true });
|
||||
outlet = React.cloneElement(child);
|
||||
} else if (child.type === Fragment && child.props.children[0].type === IonRouterOutlet) {
|
||||
outlet = child.props.children[0];
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import './theme/variables.css';
|
||||
import Main from './pages/Main';
|
||||
import OverlayHooks from './pages/overlay-hooks/OverlayHooks';
|
||||
import OverlayComponents from './pages/overlay-components/OverlayComponents';
|
||||
import Tabs from './pages/Tabs';
|
||||
|
||||
setupIonicReact();
|
||||
|
||||
@@ -33,6 +34,7 @@ const App: React.FC = () => (
|
||||
<Route path="/" component={Main} />
|
||||
<Route path="/overlay-hooks" component={OverlayHooks} />
|
||||
<Route path="/overlay-components" component={OverlayComponents} />
|
||||
<Route path="/tabs" component={Tabs} />
|
||||
</IonReactRouter>
|
||||
</IonApp>
|
||||
);
|
||||
|
||||
60
packages/react/test-app/src/pages/Tabs.tsx
Normal file
60
packages/react/test-app/src/pages/Tabs.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
import { IonContent, IonHeader, IonLabel, IonPage, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs, IonTitle, IonToolbar } from '@ionic/react';
|
||||
import React from 'react';
|
||||
import { Redirect, Route } from 'react-router';
|
||||
|
||||
const Tab1: React.FC = () => (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>
|
||||
Tab 1
|
||||
</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonLabel>Tab 1 page</IonLabel>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
|
||||
const Tab2: React.FC = () => (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>
|
||||
Tab 2
|
||||
</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonLabel>Tab 2 page</IonLabel>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
|
||||
const Tabs: React.FC = () => (
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
<Route exact path="/tabs/tab1">
|
||||
<Tab1 />
|
||||
</Route>
|
||||
<Route exact path="/tabs/tab2">
|
||||
<Tab2 />
|
||||
</Route>
|
||||
<Route exact path="/tabs">
|
||||
<Redirect to ="/tabs/tab1" />
|
||||
</Route>
|
||||
</IonRouterOutlet>
|
||||
<IonTabBar slot="bottom">
|
||||
<IonTabButton tab="tab1" href="/tabs/tab1">
|
||||
<IonLabel>Tab 1</IonLabel>
|
||||
</IonTabButton>
|
||||
<IonTabButton tab="tab2" href="/tabs/tab2">
|
||||
<IonLabel>Tab 2</IonLabel>
|
||||
</IonTabButton>
|
||||
</IonTabBar>
|
||||
</IonTabs>
|
||||
)
|
||||
|
||||
export default Tabs;
|
||||
Reference in New Issue
Block a user