Skip to main content

Command Palette

Search for a command to run...

How to Persist Navigation State in React Native and React Navigation 5

Published
2 min read
How to Persist Navigation State in React Native and React Navigation 5
Y

I am a React / React Native Software Engineer

scale

You might want to save the navigation state in the app, so that the same screen is show after the app is restarted.

In this article we will go through a sample application just to do this.

Snack of the application: https://snack.expo.io/eICO2XnKx

Requirements:

  • react-navigation 5

We can use onStateChange and initialState props of the NavigationContainer to implement this functionality.

  • onStateChange - function notifies of any state changes. We can persist the state in this callback.

  • initialState - This property allows us to pass an initial state to use for navigation state. We can pass the restored state value in this property.

Let’s create two screens HomeScreen and DetailsScreen.

Home.js

// screens/Home.js
import * as React from 'react';
import { View, Text, Button } from 'react-native';

export function HomeScreen({ navigation }) {

return (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Home Screen</Text>
    <Button
      title="Go to Details"
      onPress={() => navigation.navigate('Details')}
    />
  </View>
 );

}

Details.js

// screens/Details.js
import * as React from 'react';
import { View, Text, Button } from 'react-native';

export function DetailsScreen({ navigation }) {

return (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Details Screen</Text>
    <Button
      title="Go to Home"
      onPress={() => navigation.navigate('Home')}
    />
  </View>
 );

}

Create a stack navigator to navigate between the screens.

AppNavigation.js

*// navigation/AppNavigation.js
*import * as React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { HomeScreen } from '../screens/Home';
import { DetailsScreen } from '../screens/Details';

const Stack = createStackNavigator();

export function AppNavigation(){
 return (
  <Stack.Navigator>
    <Stack.Screen name="Home" component={HomeScreen} />
    <Stack.Screen name="Details" component={DetailsScreen} />                </Stack.Navigator>
 )
}

Let’s now restore and save navigation state in App.js

import * as React from 'react';
import { Linking, Platform, ActivityIndicator } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer } from '@react-navigation/native';
const PERSISTENCE_KEY = 'NAVIGATION_STATE';

import { AppNavigation } from './navigation/AppNavigation';


export default function App() {
  const [isReady, setIsReady] = React.useState(false);
  const [initialState, setInitialState] = React.useState();

  React.useEffect(() => {
    const restoreState = async () => {
      try {
        const initialUrl = await Linking.getInitialURL();

        if (Platform.OS !== 'web' && initialUrl == null) {
          // Only restore state if there's no deep link and we're not on web
          const savedStateString = await AsyncStorage.getItem(PERSISTENCE_KEY);
          const state = savedStateString
            ? JSON.parse(savedStateString)
            : undefined;

          if (state !== undefined) {
            setInitialState(state);
          }
        }
      } finally {
        setIsReady(true);
      }
    };

    if (!isReady) {
      restoreState();
    }
  }, [isReady]);

  if (!isReady) {
    return <ActivityIndicator/>;
  }

  return (
    <NavigationContainer
      initialState={initialState}
      onStateChange={(state) =>
        AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
      }>
     <AppNavigation/>
    </NavigationContainer>
  );
}

Reference: