BrightLights
BrightLights

Reputation: 3

What can I do to stop my React-Native Navigation from increasing consumed memory (RAM)?

Recently I have been building a larger scale project using react-native (0.77.1)without leveraging any framework. i.e. bare-workflow. I faced the known issue, that during sessions of interacting with the app ( mainly navigating ) the application was leaking memory because of navigating in my Stack Navigator's Screens. I am using react-navigation ( https://reactnavigation.org/ ) and have declared my Navigator as the following

<Stack.Navigator detachInactiveScreens={true}>

Even in a tiny dummy application, which I have included below, if ran in XCode and navigated sufficiently ( ~15 times ), the initially required 100mb of memory (RAM) will grow to reach 190mb and continue to grow on further, without ever dropping.

I was thinking it might be caused by the headers not being properly cleared after navigating to a new page, or that perhaps the <Stack.Navigator> would be saving all of the visited Screens in the background.

Perhaps this is an already resolved issue. But it would be tremendously helpful to continue my project's journey, especially because I am still quite new to react-native. Many Thanks <3

import React from "react";
import { Button, View } from "react-native";

import { enableScreens } from 'react-native-screens';

enableScreens();

import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { SafeAreaProvider } from 'react-native-safe-area-context';

import ScreenOne from "./src/screens/ScreenOne";
import ScreenTwo from "./src/screens/ScreenTwo";
//These are just simple components displaying each a piece of <Text>

export default function App() {
const Stack = createStackNavigator();

  return (
    <SafeAreaProvider>
      <NavigationContainer>
        <Stack.Navigator detachInactiveScreens={true}>
          <Stack.Screen name="screen-1" component={ScreenOne} options={({navigation}) => ({
              headerLeft: () => (
                  <Button title="go to s2" onPress={() => {
                    navigation.setOptions({headerLeft: undefined})
                    navigation.navigate("screen-2")}}/>
              )
          })}/>
          <Stack.Screen name="screen-2" component={ScreenTwo} options={({navigation}) => ({
              headerLeft: () => (
                <Button title="go to s2" onPress={() => {
                  navigation.setOptions({headerLeft: undefined})
                  navigation.navigate("screen-1")}}/>
              )
          })}/>
        </Stack.Navigator>
      </NavigationContainer>
    </SafeAreaProvider>
  )
}

Upvotes: 0

Views: 43

Answers (2)

BrightLights
BrightLights

Reputation: 3

@Eternal Dreamer's Solution did solve a big fraction of the Issue. Additionally, I went over the Documentation of react-navigation/native at https://reactnavigation.org/ to learn how to effectively use the Stack Navigator. Summarized up I:

  1. Moved const Stack = createStackNavigator(); out of my React components like export default function App(){...}, as suggested
  2. Leveraged the use of navigation.goBack() and .popTo() as these functions discard loaded pages from the Stack, hence freeing memory
  3. Reducing the amount of nested Navigators in my project. Example: I only kept one for defining many settings-options routes, which only have to be loaded, when the main Settings screen is opened.
  4. Reduced the amount of const *name* = useNavigation() calls in different components like a custom-header and migrated to passing a navigation element to such elements via their definition. Example: export const *ExampleHeader* = ({ navigation }: { navigation: NativeStackNavigationProp<any> }) => { return *The Headers Options*

In the end, the Application will always consume a bit of memory when rendering new components or a new page.

Upvotes: 0

Eternal Dreamer
Eternal Dreamer

Reputation: 483

I bet your mistake is simply that createStackNavigator() shall be apart from any component ;

...
import ScreenOne from "./src/screens/ScreenOne";
import ScreenTwo from "./src/screens/ScreenTwo";


const Stack = createStackNavigator();

export default function App() {
  return (
    <SafeAreaProvider>
...

You might want to take look at the documentation.

Otherwise, you may check out this similar question

Upvotes: 0

Related Questions