From 1c7d1e5cf1ad7e53ebbee2566e8fa89f567f7fb5 Mon Sep 17 00:00:00 2001 From: Ely Lucas Date: Mon, 9 Dec 2019 14:36:47 -0700 Subject: [PATCH] fix(react): first render performance improvements --- core/src/components/tabs/readme.md | 58 +++-- .../src/ReactRouter/IonRouteAction.ts | 1 + .../src/ReactRouter/NavManager.tsx | 9 +- .../react-router/src/ReactRouter/Router.tsx | 217 ++++++++++-------- .../src/ReactRouter/StackManager.tsx | 20 +- .../react-router/src/ReactRouter/View.tsx | 15 -- .../react-router/src/ReactRouter/ViewItem.ts | 5 +- .../src/ReactRouter/ViewStacks.ts | 1 - packages/react-router/tslint.json | 4 +- .../src/components/navigation/IonTabBar.tsx | 2 +- packages/react/src/contexts/NavContext.ts | 2 +- 11 files changed, 160 insertions(+), 174 deletions(-) create mode 100644 packages/react-router/src/ReactRouter/IonRouteAction.ts diff --git a/core/src/components/tabs/readme.md b/core/src/components/tabs/readme.md index 0949efcbaed..48a37bd8454 100644 --- a/core/src/components/tabs/readme.md +++ b/core/src/components/tabs/readme.md @@ -176,38 +176,34 @@ will match the following tab: ### React ```tsx +import React from 'react'; +import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, IonBadge } from '@ionic/react'; + export const TabsExample: React.FC = () => ( - - - - {/* - Using the render method prop cuts down the number of renders your components will have due to route changes. - Use the component prop when your component depends on the RouterComponentProps passed in automatically. - */} - } exact={true} /> - } exact={true} /> - } exact={true} /> - } exact={true} /> - - - - - Schedule - - - - Speakers - - - - Map - - - - About - - - + + + + + Schedule + 6 + + + + + Speakers + + + + + Map + + + + + About + + + ); ``` diff --git a/packages/react-router/src/ReactRouter/IonRouteAction.ts b/packages/react-router/src/ReactRouter/IonRouteAction.ts new file mode 100644 index 00000000000..7e03063166e --- /dev/null +++ b/packages/react-router/src/ReactRouter/IonRouteAction.ts @@ -0,0 +1 @@ +export type IonRouteAction = 'push' | 'replace' | 'pop'; diff --git a/packages/react-router/src/ReactRouter/NavManager.tsx b/packages/react-router/src/ReactRouter/NavManager.tsx index edcb6461735..23ac122330f 100644 --- a/packages/react-router/src/ReactRouter/NavManager.tsx +++ b/packages/react-router/src/ReactRouter/NavManager.tsx @@ -4,11 +4,12 @@ import { Location as HistoryLocation, UnregisterCallback } from 'history'; import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; +import { IonRouteAction } from './IonRouteAction'; import { StackManager } from './StackManager'; interface NavManagerProps extends RouteComponentProps { onNavigateBack: (defaultHref?: string) => void; - onNavigate: (type: 'push' | 'replace', path: string, state?: any) => void; + onNavigate: (type: 'push' | 'replace' | 'pop', path: string, state?: any) => void; } export class NavManager extends React.Component { @@ -24,7 +25,7 @@ export class NavManager extends React.Component { return; }, // overridden in View for each IonPage + registerIonPage: () => { return; } // overridden in View for each IonPage }; this.listenUnregisterCallback = this.props.history.listen((location: HistoryLocation) => { @@ -52,8 +53,8 @@ export class NavManager extends React.Component { listenUnregisterCallback: UnregisterCallback | undefined; activeIonPageId?: string; - currentDirection?: RouterDirection; + currentIonRouteAction?: IonRouteAction; + currentRouteDirection?: RouterDirection; locationHistory = new LocationHistory(); - routes: { [key: string]: any; } = {}; + routes: { [key: string]: React.ReactElement; } = {}; + ionPageElements: { [key: string]: HTMLElement; } = {}; + routerOutlets: { [key: string]: HTMLIonRouterOutletElement; } = {}; + firstRender = true; constructor(props: RouteComponentProps) { super(props); @@ -52,7 +57,8 @@ class RouteManager extends React.Component { - if (routerOutlet.componentOnReady) { - routerOutlet.dispatchEvent(new Event('routerOutletReady')); - return; - } else { - setTimeout(() => { - waitUntilReady(); - }, 0); - } - }; - - await waitUntilReady(); const canStart = () => { const config = getConfig(); @@ -329,20 +324,13 @@ class RouteManager extends React.Component { - const viewStacks = Object.assign(new ViewStacks(), state.viewStacks); - const { view } = viewStacks.findViewInfoById(viewId); - - view!.ionPageElement = page; - view!.isIonRoute = true; - - return { - viewStacks - }; - - }, () => { - this.setActiveView(this.state.location || this.props.location, this.state.action!); - }); + const viewStacks = Object.assign(new ViewStacks(), this.state.viewStacks); + const { view } = viewStacks.findViewInfoById(viewId); + if (view) { + view.isIonRoute = true; + this.ionPageElements[view.id] = page; + this.setActiveView(this.state.location || this.props.location, this.state.action!, viewStacks); + } } syncRoute(_id: string, routerOutlet: any) { @@ -359,43 +347,62 @@ class RouteManager extends React.Component