Skip to content

Commit

Permalink
refactor: convert MainDrawerNavigator to class to avoid route.state
Browse files Browse the repository at this point in the history
… usage

Keep the Report Screen mounted since the first time it's resolved

The Report Screen is setup to mount when:
- routing information is already available
- initial params provide fallback when routing information is missing

This would keep the Report Screen mounted in case the `initialReportID` is
ever reset to `null` like in the event of clearing Onyx data
  • Loading branch information
kidroca committed Apr 28, 2021
1 parent b20db83 commit a2aa335
Showing 1 changed file with 56 additions and 52 deletions.
108 changes: 56 additions & 52 deletions src/libs/Navigation/AppNavigator/MainDrawerNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,10 @@ import SCREENS from '../../../SCREENS';
import SidebarScreen from '../../../pages/home/sidebar/SidebarScreen';
import ReportScreen from '../../../pages/home/ReportScreen';

const LoadingScreen = React.memo(() => <FullScreenLoadingIndicator visible />, () => true);

const propTypes = {
// Initial report to be used if nothing else is specified by routing
initialReportID: PropTypes.string,

// Route data passed by react navigation
route: PropTypes.shape({
state: PropTypes.shape({
// A list of mounted screen names
routeNames: PropTypes.arrayOf(PropTypes.string),
}),
}).isRequired,

...windowDimensionsPropTypes,
};

Expand All @@ -40,56 +30,70 @@ const defaultProps = {
};

const Drawer = createDrawerNavigator();
const LoadingScreen = React.memo(() => <FullScreenLoadingIndicator visible />, () => true);

/**
* Derives whether it's time to mount the ReportScreen from current component props
*
* @param {String} initialReportID
* @param {Object} route
* @returns {boolean}
*/
const shouldMountReportScreen = ({initialReportID, route}) => {
if (_.isString(initialReportID)) {
return true;
class MainDrawerNavigator extends React.Component {
constructor(props) {
super(props);
this.shouldMountReportScreen = _.isString(props.initialReportID);
}

// After the ReportScreen is mounted it should stay mounted no matter initial report ID
return Boolean(route.state) && route.state.routeNames.includes(SCREENS.REPORT);
};
shouldComponentUpdate(nextProps) {
// Once the report screen is mounted we don't unmount it
if (!this.shouldMountReportScreen) {
this.shouldMountReportScreen = _.isString(nextProps.initialReportID);

const MainDrawerNavigator = props => (
<Drawer.Navigator
openByDefault
drawerType={getNavigationDrawerType(props.isSmallScreenWidth)}
drawerStyle={getNavigationDrawerStyle(
props.windowWidth,
props.isSmallScreenWidth,
)}
sceneContainerStyle={styles.navigationSceneContainer}
edgeWidth={500}
drawerContent={() => <SidebarScreen />}
screenOptions={{
cardStyle: styles.navigationScreenCardStyle,
headerShown: false,
}}
>
{
shouldMountReportScreen(props)
? (
<Drawer.Screen
name={SCREENS.REPORT}
component={ReportScreen}
initialParams={{reportID: props.initialReportID}}
/>
)
: <Drawer.Screen name={SCREENS.LOADING} component={LoadingScreen} />
if (this.shouldMountReportScreen) {
return true;
}
}
</Drawer.Navigator>
);

// Re-render the component only for these changes
const shouldUpdateForProps = ['windowWidth', 'isSmallScreenWidth'];

const areEqual = _.isEqual(
_.pick(this.props, ...shouldUpdateForProps),
_.pick(nextProps, ...shouldUpdateForProps),
);

return !areEqual;
}

render() {
return (
<Drawer.Navigator
openByDefault
drawerType={getNavigationDrawerType(this.props.isSmallScreenWidth)}
drawerStyle={getNavigationDrawerStyle(
this.props.windowWidth,
this.props.isSmallScreenWidth,
)}
sceneContainerStyle={styles.navigationSceneContainer}
edgeWidth={500}
drawerContent={() => <SidebarScreen />}
screenOptions={{
cardStyle: styles.navigationScreenCardStyle,
headerShown: false,
}}
>
{
this.shouldMountReportScreen
? (
<Drawer.Screen
name={SCREENS.REPORT}
component={ReportScreen}
initialParams={{reportID: this.props.initialReportID}}
/>
)
: <Drawer.Screen name={SCREENS.LOADING} component={LoadingScreen} />
}
</Drawer.Navigator>
);
}
}

MainDrawerNavigator.propTypes = propTypes;
MainDrawerNavigator.defaultProps = defaultProps;
MainDrawerNavigator.displayName = 'MainDrawerNavigator';
export default compose(
withWindowDimensions,
withOnyx({
Expand Down

0 comments on commit a2aa335

Please sign in to comment.