Skip to content

Commit

Permalink
Merge pull request #107 from software-mansion-labs/poc/split-perf
Browse files Browse the repository at this point in the history
split navigators performance
  • Loading branch information
adamgrzybowski authored Oct 9, 2024
2 parents 7b36a3b + 93eb244 commit 59df51e
Show file tree
Hide file tree
Showing 11 changed files with 55 additions and 83 deletions.
10 changes: 0 additions & 10 deletions src/components/withPrepareCentralPaneScreen/index.tsx

This file was deleted.

11 changes: 5 additions & 6 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import ComposeProviders from '@components/ComposeProviders';
import OptionsListContextProvider from '@components/OptionListContextProvider';
import {SearchContextProvider} from '@components/Search/SearchContext';
import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal';
import withPrepareCentralPaneScreen from '@components/withPrepareCentralPaneScreen';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
import useOnboardingFlowRouter from '@hooks/useOnboardingFlow';
import usePermissions from '@hooks/usePermissions';
Expand All @@ -24,6 +23,7 @@ import KeyboardShortcut from '@libs/KeyboardShortcut';
import Log from '@libs/Log';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import getOnboardingModalScreenOptions from '@libs/Navigation/getOnboardingModalScreenOptions';
import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT';
import Navigation from '@libs/Navigation/Navigation';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import NetworkConnection from '@libs/NetworkConnection';
Expand Down Expand Up @@ -56,7 +56,6 @@ import type * as OnyxTypes from '@src/types/onyx';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
import SIDEBAR_TO_SPLIT from '../linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT';
import createCustomStackNavigator from './createCustomStackNavigator';
import defaultScreenOptions from './defaultScreenOptions';
import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions';
Expand All @@ -79,10 +78,10 @@ const loadReportAvatar = () => require<ReactComponentModule>('../../../pages/Rep
const loadReceiptView = () => require<ReactComponentModule>('../../../pages/TransactionReceiptPage').default;
const loadWorkspaceJoinUser = () => require<ReactComponentModule>('@pages/workspace/WorkspaceJoinUserPage').default;

const loadReportSplitNavigator = withPrepareCentralPaneScreen(() => require<ReactComponentModule>('./Navigators/ReportsSplitNavigator').default);
const loadSettingsSplitNavigator = withPrepareCentralPaneScreen(() => require<ReactComponentModule>('./Navigators/SettingsSplitNavigator').default);
const loadWorkspaceSplitNavigator = withPrepareCentralPaneScreen(() => require<ReactComponentModule>('./Navigators/WorkspaceSplitNavigator').default);
const loadSearchPage = withPrepareCentralPaneScreen(() => require<ReactComponentModule>('@pages/Search/SearchPage').default);
const loadReportSplitNavigator = () => require<ReactComponentModule>('./Navigators/ReportsSplitNavigator').default;
const loadSettingsSplitNavigator = () => require<ReactComponentModule>('./Navigators/SettingsSplitNavigator').default;
const loadWorkspaceSplitNavigator = () => require<ReactComponentModule>('./Navigators/WorkspaceSplitNavigator').default;
const loadSearchPage = () => require<ReactComponentModule>('@pages/Search/SearchPage').default;

function shouldOpenOnAdminRoom() {
const url = getCurrentUrl();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, {useRef} from 'react';
import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen';
import withPrepareCentralPaneScreen from '@components/withPrepareCentralPaneScreen';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
import usePermissions from '@hooks/usePermissions';
import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator';
Expand All @@ -12,7 +11,7 @@ import CONST from '@src/CONST';
import SCREENS from '@src/SCREENS';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';

const loadReportScreen = withPrepareCentralPaneScreen(() => require<ReactComponentModule>('../../../../pages/home/ReportScreen').default);
const loadReportScreen = () => require<ReactComponentModule>('../../../../pages/home/ReportScreen').default;

const Stack = createSplitStackNavigator<ReportsSplitNavigatorParamList>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea
import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
import {StackView} from '@react-navigation/stack';
import React from 'react';
import React, {useMemo} from 'react';
import CustomRouter from './CustomRouter';
import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types';

function getStateToRender(state: StackNavigationState<ParamListBase>): StackNavigationState<ParamListBase> {
const routes = state.routes.slice(-2);

return {
...state,
routes,
index: routes.length - 1,
};
}

function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
// TODO: This part needs some TS magic to work.
const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
StackNavigationState<ParamListBase>,
ResponsiveStackNavigatorRouterOptions,
Expand All @@ -20,12 +29,14 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
initialRouteName: props.initialRouteName,
});

const stateToRender = useMemo(() => getStateToRender(state), [state]);

return (
<NavigationContent>
<StackView
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
state={state}
state={stateToRender}
descriptors={descriptors}
navigation={navigation}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import getIsNarrowLayout from '@libs/getIsNarrowLayout';
import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute';
import navigationRef from '@libs/Navigation/navigationRef';
import type {SplitStackNavigatorRouterOptions} from './types';
import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState';

type StackState = StackNavigationState<ParamListBase> | PartialState<StackNavigationState<ParamListBase>>;

Expand Down Expand Up @@ -94,7 +95,8 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) {
return stackRouter.getStateForAction(state, action, configOptions);
},
getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) {
const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList});
const preservedState = getPreservedSplitNavigatorState(options.parentRoute.key);
const initialState = preservedState ?? stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList});

adaptStateIfNecessary({
state: initialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import SplitStackRouter from './SplitStackRouter';
import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types';
import useHandleScreenResize from './useHandleScreenResize';
import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren';
import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState';

function getStateToRender(state: StackNavigationState<ParamListBase>, isSmallScreenWidth: boolean): StackNavigationState<ParamListBase> {
const sidebarScreenRoute = state.routes.at(0);
Expand Down Expand Up @@ -56,6 +57,8 @@ function SplitStackNavigator<ParamList extends ParamListBase>(props: SplitStackN
parentRoute: route,
});

// We need to copy the state to the params so that the state is preserved when the root navigator unmount this route for performance reasons.
usePreserveSplitNavigatorState(route, state);
useHandleScreenResize(navigation);

const stateToRender = useMemo(() => getStateToRender(state, shouldUseNarrowLayout), [state, shouldUseNarrowLayout]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type {NavigationState, ParamListBase, RouteProp, StackNavigationState} from '@react-navigation/native';
import {useEffect} from 'react';

const preservedSplitNavigatorStates: Record<string, StackNavigationState<ParamListBase>> = {};

const cleanPreservedSplitNavigatorStates = (state: NavigationState) => {
const currentSplitNavigatorKeys = state.routes.map((route) => route.key);

for (const key of Object.keys(preservedSplitNavigatorStates)) {
if (!currentSplitNavigatorKeys.includes(key)) {
delete preservedSplitNavigatorStates[key];
}
}
};

const getPreservedSplitNavigatorState = (key: string) => preservedSplitNavigatorStates[key];

function usePreserveSplitNavigatorState(route: RouteProp<ParamListBase>, state: StackNavigationState<ParamListBase>) {
useEffect(() => {
preservedSplitNavigatorStates[route.key] = state;
}, [route, state]);
}

export default usePreserveSplitNavigatorState;

export {getPreservedSplitNavigatorState, cleanPreservedSplitNavigatorStates};
30 changes: 0 additions & 30 deletions src/libs/Navigation/FreezeWrapper.tsx

This file was deleted.

2 changes: 2 additions & 0 deletions src/libs/Navigation/NavigationRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import AppNavigator from './AppNavigator';
import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState';
import linkingConfig from './linkingConfig';
import customGetPathFromState from './linkingConfig/customGetPathFromState';
import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath';
Expand Down Expand Up @@ -165,6 +166,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh

// We want to clean saved scroll offsets for screens that aren't anymore in the state.
cleanStaleScrollOffsets(state);
cleanPreservedSplitNavigatorStates(state);
};

return (
Expand Down
24 changes: 0 additions & 24 deletions src/libs/freezeScreenWithLazyLoading.tsx

This file was deleted.

8 changes: 1 addition & 7 deletions src/pages/home/sidebar/SidebarScreen/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import React from 'react';
// import FreezeWrapper from '@libs/Navigation/FreezeWrapper';
import BaseSidebarScreen from './BaseSidebarScreen';

// TODO-SPLITS: Figure out how to handle the FreezeWrapper component.
function SidebarScreen() {
return (
// <FreezeWrapper>
<BaseSidebarScreen />
// </FreezeWrapper>
);
return <BaseSidebarScreen />;
}

SidebarScreen.displayName = 'SidebarScreen';
Expand Down

0 comments on commit 59df51e

Please sign in to comment.