From 01f8a7c55865f4053b27deff0912f43cc537e0f1 Mon Sep 17 00:00:00 2001 From: Yohan Simard Date: Tue, 11 Feb 2020 01:05:24 +0100 Subject: [PATCH 1/5] Tried to improve performance... --- App.js | 9 ++- components/BaseContainer.js | 18 +++--- components/CustomHeader.js | 32 +++++++--- components/CustomMaterialIcon.js | 9 +++ components/DashboardItem.js | 8 ++- components/FetchedDataSectionList.js | 75 +++++++++++++---------- components/Sidebar.js | 33 +++++++--- components/WebViewScreen.js | 1 + screens/HomeScreen.js | 55 +++++++++++------ screens/PlanningDisplayScreen.js | 6 +- screens/PlanningScreen.js | 57 +++++++++++------ screens/Proximo/ProximoListScreen.js | 92 ++++++++++++++++++---------- screens/Proximo/ProximoMainScreen.js | 16 +++-- screens/Proxiwash/ProxiwashScreen.js | 11 +++- screens/SelfMenuScreen.js | 2 +- 15 files changed, 284 insertions(+), 140 deletions(-) diff --git a/App.js b/App.js index 5de5714..ac44a28 100644 --- a/App.js +++ b/App.js @@ -34,6 +34,9 @@ export default class App extends React.Component { constructor(props: Object) { super(props); LocaleManager.initTranslations(); + this.onIntroDone = this.onIntroDone.bind(this); + this.loadAssetsAsync = this.loadAssetsAsync.bind(this); + this.onLoadFinished = this.onLoadFinished.bind(this); } /** @@ -102,14 +105,14 @@ export default class App extends React.Component { if (this.state.isLoading) { return ( this.loadAssetsAsync()} - onFinish={() => this.onLoadFinished()} + startAsync={this.loadAssetsAsync} + onFinish={this.onLoadFinished} onError={console.warn} /> ); } if (this.state.showIntro || this.state.showUpdate) { - return this.onIntroDone()} + return ; } else { const AppNavigator = createAppContainerWithInitialRoute(AsyncStorageManager.getInstance().preferences.defaultStartScreen.current); diff --git a/components/BaseContainer.js b/components/BaseContainer.js index 1e4fa85..4da6b7e 100644 --- a/components/BaseContainer.js +++ b/components/BaseContainer.js @@ -30,7 +30,6 @@ type State = { export default class BaseContainer extends React.Component { - static defaultProps = { headerRightButton: , hasTabs: false, @@ -46,9 +45,15 @@ export default class BaseContainer extends React.Component { isHeaderVisible: true, }; + constructor() { + super(); + this.toggle = this.toggle.bind(this); + } + toggle() { this.props.navigation.toggleDrawer(); } + /** * Register for blur event to close side menu on screen change */ @@ -93,7 +98,9 @@ export default class BaseContainer extends React.Component { this.willFocusSubscription.remove(); } - getMainContainer() { + + render() { + // console.log("rendering BaseContainer"); return ( {this.state.isHeaderVisible ? @@ -104,7 +111,7 @@ export default class BaseContainer extends React.Component { leftButton={ this.toggle()}> + onPress={this.toggle}> @@ -118,9 +125,4 @@ export default class BaseContainer extends React.Component { ); } - - - render() { - return (this.getMainContainer()); - } } diff --git a/components/CustomHeader.js b/components/CustomHeader.js index 0290c89..fd5c74f 100644 --- a/components/CustomHeader.js +++ b/components/CustomHeader.js @@ -32,7 +32,6 @@ type Props = { * @prop navigation {Object} The navigation object from react navigation */ export default class CustomHeader extends React.Component { - static defaultProps = { hasBackButton: false, hasSearchField: false, @@ -45,9 +44,25 @@ export default class CustomHeader extends React.Component { hasTabs: false, }; + constructor() { + super(); + this.onPressBack = this.onPressBack.bind(this); + } + + shouldComponentUpdate(nextProps: Props): boolean { + return nextProps.title !== this.props.title || + nextProps.subtitle !== this.props.subtitle || + nextProps.hasBackButton !== this.props.hasBackButton || + nextProps.hasSearchField !== this.props.hasSearchField || + nextProps.shouldFocusSearchBar !== this.props.shouldFocusSearchBar || + nextProps.hasTabs !== this.props.hasTabs || + nextProps.rightButton !== this.props.rightButton || + nextProps.leftButton !== this.props.leftButton; + } + componentDidMount() { if (this.refs.searchInput !== undefined && this.refs.searchInput._root !== undefined && this.props.shouldFocusSearchBar) { - // does not work if called to early for some reason... + // does not work if called too early for some reason... setTimeout(() => this.refs.searchInput._root.focus(), 500); } } @@ -67,7 +82,7 @@ export default class CustomHeader extends React.Component { ref="searchInput" placeholder={i18n.t('proximoScreen.search')} placeholderTextColor={ThemeManager.getCurrentThemeVariables().toolbarPlaceholderColor} - onChangeText={(text) => this.props.searchCallback(text)}/> + onChangeText={this.props.searchCallback}/> ); @@ -87,17 +102,20 @@ export default class CustomHeader extends React.Component { } + onPressBack() { + const backAction = NavigationActions.back(); + this.props.navigation.dispatch(backAction); + } + render() { + console.log("rendering CustomHeader"); let button; // Does the app have a back button or a burger menu ? if (this.props.hasBackButton) button = { - const backAction = NavigationActions.back(); - this.props.navigation.dispatch(backAction); - }}> + onPress={this.onPressBack}> diff --git a/components/CustomMaterialIcon.js b/components/CustomMaterialIcon.js index e6919f2..4792b81 100644 --- a/components/CustomMaterialIcon.js +++ b/components/CustomMaterialIcon.js @@ -30,7 +30,16 @@ export default class CustomMaterialIcon extends React.Component { width: 30, }; + shouldComponentUpdate(nextProps: Props): boolean { + return nextProps.icon !== this.props.icon || + nextProps.active !== this.props.active || + nextProps.width !== this.props.width || + nextProps.fontSize !== this.props.fontSize || + nextProps.color !== this.props.color; + } + render() { + // console.log("rendering icon " + this.props.icon); return ( { - static defaultProps = { isSquare: false, isSquareLeft: true, displayEvent: undefined, }; + shouldComponentUpdate(nextProps: Props): boolean { + return nextProps.isAvailable !== this.props.isAvailable || + nextProps.subtitle !== this.props.subtitle; + } + + /** * Convert the date string given by in the event list json to a date object * @param dateString @@ -203,6 +208,7 @@ export default class DashboardItem extends React.Component { render() { + // console.log("rendering DashboardItem " + this.props.title); let marginRight = 10; if (this.props.isSquare) { if (this.props.isSquareLeft) diff --git a/components/FetchedDataSectionList.js b/components/FetchedDataSectionList.js index 65f6e7a..781f504 100644 --- a/components/FetchedDataSectionList.js +++ b/components/FetchedDataSectionList.js @@ -25,7 +25,6 @@ type State = { * Used by inheriting from it and redefining getters. */ export default class FetchedDataSectionList extends React.Component { - webDataManager: WebDataManager; willFocusSubscription: function; @@ -46,8 +45,22 @@ export default class FetchedDataSectionList extends React.Component { - this.onScreenFocus(); - } - ); + 'willFocus', this.onScreenFocus.bind(this)); this.willBlurSubscription = this.props.navigation.addListener( - 'willBlur', - () => { - this.onScreenBlur(); - } - ); + 'willBlur', this.onScreenBlur.bind(this)); } /** @@ -93,7 +98,7 @@ export default class FetchedDataSectionList extends React.Component 0) - this.refreshInterval = setInterval(() => this._onRefresh(), this.refreshTime) + this.refreshInterval = setInterval(this._onRefresh.bind(this), this.refreshTime) } /** @@ -117,7 +122,7 @@ export default class FetchedDataSectionList extends React.Component { + _onRefresh() { let canRefresh; if (this.lastRefresh !== undefined) canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh; @@ -144,8 +149,7 @@ export default class FetchedDataSectionList extends React.Component; } @@ -222,6 +225,11 @@ export default class FetchedDataSectionList extends React.Component item.text, + keyExtractor: this.datasetKeyExtractor, } ]; } @@ -275,6 +283,19 @@ export default class FetchedDataSectionList extends React.Component : + this.getRenderSectionHeader(title) + } + + renderItem(isEmpty, {item, section}) { + return isEmpty ? + this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) : + this.getRenderItem(item, section) + } + /** * Get the section list render using the generated dataset * @@ -295,16 +316,8 @@ export default class FetchedDataSectionList extends React.Component } - renderSectionHeader={({section: {title}}) => - isEmpty ? - : - this.getRenderSectionHeader(title) - } - renderItem={({item, section}) => - isEmpty ? - this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) : - this.getRenderItem(item, section, dataset) - } + renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty} + renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty} style={{minHeight: 300, width: '100%'}} contentContainerStyle={ isEmpty ? @@ -351,11 +364,12 @@ export default class FetchedDataSectionList extends React.Component ); } - } diff --git a/components/Sidebar.js b/components/Sidebar.js index 2edcc0c..61cd73f 100644 --- a/components/Sidebar.js +++ b/components/Sidebar.js @@ -103,21 +103,35 @@ export default class SideBar extends React.Component { icon: "information", }, ]; + this.getRenderItem = this.getRenderItem.bind(this); } - getRenderItem(item: Object) { + shouldComponentUpdate(nextProps: Props, nextState: State): boolean { + return nextState.active !== this.state.active; + } + + + onListItemPress(item) { + if (item.link !== undefined) + Linking.openURL(item.link).catch((err) => console.error('Error opening link', err)); + else + this.navigateToScreen(item.route); + } + + + listKeyExtractor(item) { + return item.route; + } + + + getRenderItem({item}: Object) { if (item.icon !== undefined) { return ( { - if (item.link !== undefined) - Linking.openURL(item.link).catch((err) => console.error('Error opening link', err)); - else - this.navigateToScreen(item.route); - }} + onPress={this.onListItemPress.bind(this, item)} > { }; render() { + // console.log("rendering SideBar"); return ( { item.route} - renderItem={({item}) => this.getRenderItem(item)} + keyExtractor={this.listKeyExtractor} + renderItem={this.getRenderItem} /> ); diff --git a/components/WebViewScreen.js b/components/WebViewScreen.js index 480c425..b908e69 100644 --- a/components/WebViewScreen.js +++ b/components/WebViewScreen.js @@ -133,6 +133,7 @@ export default class WebViewScreen extends React.Component { } render() { + // console.log("rendering WebViewScreen"); const nav = this.props.navigation; this.webviewArray = []; return ( diff --git a/screens/HomeScreen.js b/screens/HomeScreen.js index 6a2ef12..dcad00c 100644 --- a/screens/HomeScreen.js +++ b/screens/HomeScreen.js @@ -40,6 +40,10 @@ export default class HomeScreen extends FetchedDataSectionList { constructor() { super(DATA_URL, REFRESH_TIME); + this.proxiwashClickAction = this.proxiwashClickAction.bind(this); + this.tutorinsaClickAction = this.tutorinsaClickAction.bind(this); + this.menuClickAction = this.menuClickAction.bind(this); + this.proximoClickAction = this.proximoClickAction.bind(this); } /** @@ -289,6 +293,14 @@ export default class HomeScreen extends FetchedDataSectionList { } + clickAction(isAvailable, displayEvent) { + if (isAvailable) + this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent}); + else + this.props.navigation.navigate('PlanningScreen'); + }; + + getDashboardEventItem(content: Array) { let icon = 'calendar-range'; let color = ThemeManager.getCurrentThemeVariables().planningColor; @@ -310,12 +322,6 @@ export default class HomeScreen extends FetchedDataSectionList { ; } else subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA'); - let clickAction = () => { - if (isAvailable) - this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent}); - else - this.props.navigation.navigate('PlanningScreen'); - }; let displayEvent = this.getDisplayEvent(futureEvents); @@ -324,7 +330,7 @@ export default class HomeScreen extends FetchedDataSectionList { subtitle={subtitle} color={color} icon={icon} - clickAction={() => clickAction()} + clickAction={this.clickAction.bind(this, isAvailable, displayEvent)} title={title} isAvailable={isAvailable} displayEvent={displayEvent} @@ -332,6 +338,14 @@ export default class HomeScreen extends FetchedDataSectionList { ); } + proximoClickAction() { + this.props.navigation.navigate('Proximo'); + } + + menuClickAction() { + this.props.navigation.navigate('SelfMenuScreen'); + } + getDashboardBottomItem(content: Array) { let proximoData = content[0]['data']; @@ -355,7 +369,6 @@ export default class HomeScreen extends FetchedDataSectionList { ; } else proximoSubtitle = i18n.t('homeScreen.dashboard.proximoSubtitleNA'); - let proximoClickAction = () => this.props.navigation.navigate('Proximo'); let menuIcon = 'silverware-fork-knife'; @@ -367,7 +380,6 @@ export default class HomeScreen extends FetchedDataSectionList { menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitle'); } else menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitleNA'); - let menuClickAction = () => this.props.navigation.navigate('SelfMenuScreen'); return ( menuClickAction()} + clickAction={this.menuClickAction} title={menuTitle} isAvailable={isMenuAvailable} isSquareLeft={true}/> @@ -388,13 +400,22 @@ export default class HomeScreen extends FetchedDataSectionList { subtitle={proximoSubtitle} color={proximoColor} icon={proximoIcon} - clickAction={() => proximoClickAction()} + clickAction={this.proximoClickAction} title={proximoTitle} isAvailable={isProximoAvailable}/> ); } + proxiwashClickAction() { + this.props.navigation.navigate('Proxiwash'); + } + + tutorinsaClickAction() { + this.props.navigation.navigate('TutorInsaScreen'); + } + + getDashboardMiddleItem(content: Array) { let proxiwashData = content[0]['data']; let tutorinsaData = content[1]['data']; @@ -449,7 +470,6 @@ export default class HomeScreen extends FetchedDataSectionList { ; } else proxiwashSubtitle = i18n.t('homeScreen.dashboard.proxiwashSubtitleNA'); - let proxiwashClickAction = () => this.props.navigation.navigate('Proxiwash'); let tutorinsaIcon = 'school'; let tutorinsaColor = ThemeManager.getCurrentThemeVariables().tutorinsaColor; @@ -470,7 +490,6 @@ export default class HomeScreen extends FetchedDataSectionList { ; } else tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA'); - let tutorinsaClickAction = () => this.props.navigation.navigate('TutorInsaScreen'); return ( proxiwashClickAction()} + clickAction={this.proxiwashClickAction} title={proxiwashTitle} isAvailable={proxiwashIsAvailable} isSquareLeft={true}/> @@ -492,7 +511,7 @@ export default class HomeScreen extends FetchedDataSectionList { subtitle={tutorinsaSubtitle} color={tutorinsaColor} icon={tutorinsaIcon} - clickAction={() => tutorinsaClickAction()} + clickAction={this.tutorinsaClickAction} title={tutorinsaTitle} isAvailable={tutorinsaIsAvailable}/> @@ -500,7 +519,7 @@ export default class HomeScreen extends FetchedDataSectionList { } - getRenderItem(item: Object, section: Object, data: Object) { + getRenderItem(item: Object, section: Object) { return ( section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) : {item.full_picture !== '' && item.full_picture !== undefined ? - openWebLink(item.full_picture)} +