Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@ import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName';
import type {CustomStateHookProps} from '@libs/Navigation/PlatformStackNavigation/types';

// This is an optimization to keep mounted only last few screens in the stack.
// We keep the last full screen and the one before it to avoid unmounting persistent screens
// (like ReportsSplitNavigator) which contain heavy component trees (e.g. LHN with thousands of items).
export default function useCustomRootStackNavigatorState({state}: CustomStateHookProps) {
const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name));
let indexToSlice = Math.max(0, lastSplitIndex);
const hasPrevRoute = lastSplitIndex > 0;
const isPrevFullScreen = isFullScreenName(state.routes.at(lastSplitIndex - 1)?.name);

// If the route before the last full screen is e.g. RHP, we should leave it in the rendered routes,
// as there may be display issues (blank screen) when navigating back and recreating that route to render.
if (hasPrevRoute && !isPrevFullScreen) {
indexToSlice = lastSplitIndex - 1;
}
const indexToSlice = Math.max(0, lastSplitIndex - 1);
const routesToRender = state.routes.slice(indexToSlice, state.routes.length);
return {...state, routes: routesToRender, index: routesToRender.length - 1};
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ function usePreloadFullScreenNavigators() {
}
hasPreloadedRef.current = true;
setTimeout(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is not related, but why is this timer not getting cleared on unmount?

const currentRoutes = navigation.getState().routes;
for (const tabName of TABS_TO_PRELOAD) {
// Don't preload the current tab
const isCurrentTab = TAB_TO_FULLSCREEN[tabName].includes(route.name as FullScreenName);
Expand All @@ -147,6 +148,13 @@ function usePreloadFullScreenNavigators() {
continue;
}

// Don't preload tabs whose navigator is already in the regular routes stack
const isRouteInStack = currentRoutes.some((r) => TAB_TO_FULLSCREEN[tabName].includes(r.name as FullScreenName));

if (isRouteInStack) {
continue;
Comment on lines +152 to +155

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit stack-based skip to mounted navigators

This new isRouteInStack gate treats any route present in navigation.getState().routes as already mounted, but on Android I checked src/libs/Navigation/AppNavigator/createRootStackNavigator/useCustomRootStackNavigatorState/index.android.ts and previous full-screen routes are still sliced out when the previous route is also full-screen. In flows like Inbox → Workspaces, Inbox stays in the route state but is unmounted, so this condition skips preloadTab and forces Inbox to cold-mount again when switching back, reintroducing the tab-switch performance regression for Android users.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cold-mount behavior on Android is tied to useCustomRootStackNavigatorState slicing and is not introduced or worsened by this change

}

// Preload everything else
preloadTab(tabName, navigation, subscriptionPlan);
}
Expand Down
Loading