Short answer
Use navigation.replace instead of push for repeated navigation in the same context, and freeze inactive screens with freezeOnBlur (supported by react-native-screens). Avoid keeping heavy content rendered in the background; unmountOnBlur was available in older versions but was removed in React Navigation 7.
Explanation
If users keep navigating between detail screens with navigation.push, many components and images accumulate in memory without being released. react-native-screens detaches views for hidden screens from the native view tree, and freezeOnBlur prevents background screens from rerendering. For heavy screens inside Tabs, make the heavy content conditional on useIsFocused or use lazy, rather than relying on unmountOnBlur, which is no longer available in version 7.
Code example
// Replace the current screen instead of stacking another one (checkout, confirmation, switching flows)
navigation.replace("OrderConfirmation", { orderId });
// Freeze background screens and create tab screens lazily (React Navigation 7)
<Tab.Navigator screenOptions={{ lazy: true, freezeOnBlur: true }}>
<Tab.Screen name="Feed" component={FeedScreen} />
</Tab.Navigator>
// Heavy content only while the screen is focused
function HeavyScreen() {
const isFocused = useIsFocused();
return isFocused ? <HeavyChart /> : null;
}Common mistakes
- Using navigation.push for frequently repeated transitions, filling the stack with thousands of screens and exhausting memory.
Follow-up questions
- What is the key difference between Native Stack Navigator and Stack Navigator in React Navigation?
- What are screen lifecycle events in React Navigation (useFocusEffect and useIsFocused)?