Skip to content
Merged
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
205 changes: 201 additions & 4 deletions versioned_docs/version-7.x/state-persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ title: State persistence
sidebar_label: State persistence
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

You might want to save the user's location in the app, so that they are immediately returned to the same location after the app is restarted.

This is especially valuable during development because it allows the developer to stay on the same screen when they refresh the app.
Expand All @@ -15,13 +18,192 @@ To be able to persist the [navigation state](navigation-state.md), we can use th
- `onStateChange` - This prop notifies us of any state changes. We can persist the state in this callback.
- `initialState` - This prop allows us to pass an initial state to use for [navigation state](navigation-state.md). We can pass the restored state in this prop.

<samp id="state-persistance" />
<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js
```js name="Persisting the navigation state" snack version=7 dependencies=@react-native-async-storage/async-storage
import * as React from 'react';
import { Linking, Platform } from 'react-native';
// codeblock-focus-start
import { Platform, View, Linking } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
useNavigation,
createStaticNavigation,
} from '@react-navigation/native';
// codeblock-focus-end
import { Button } from '@react-navigation/elements';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function A() {
return <View />;
}

function B() {
const navigation = useNavigation();

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('C')}>Go to C</Button>
</View>
);
}

function C() {
const navigation = useNavigation();

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('D')}>Go to D</Button>
</View>
);
}

function D() {
return <View />;
}

const HomeStackScreen = createNativeStackNavigator({
screens: {
A: A,
},
});

const SettingsStackScreen = createNativeStackNavigator({
screens: {
B: B,
C: C,
D: D,
},
});

// codeblock-focus-start

const PERSISTENCE_KEY = 'NAVIGATION_STATE_V1';

export default function App() {
const [isReady, setIsReady] = React.useState(Platform.OS === 'web'); // Don't persist state on web since it's based on URL
const [initialState, setInitialState] = React.useState();

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

if (Platform.OS !== 'web' && initialUrl == null) {
const savedState = await AsyncStorage.getItem(PERSISTENCE_KEY);
const state = savedState ? JSON.parse(savedState) : undefined;

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

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

if (!isReady) {
return null;
}
const Tab = createBottomTabNavigator({
screens: {
Home: {
screen: HomeStackScreen,
options: {
headerShown: false,
tabBarLabel: 'Home!',
},
},
Settings: {
screen: SettingsStackScreen,
options: {
headerShown: false,
tabBarLabel: 'Settings!',
},
},
},
});
const Navigation = createStaticNavigation(Tab);

return (
<Navigation
initialState={initialState}
onStateChange={(state) =>
AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
}
/>
);
}
// codeblock-focus-end
```

</TabItem>
<TabItem value="dynamic" label="Dynamic" default>

```js name="Persisting the navigation state" snack version=7 dependencies=@react-native-async-storage/async-storage
import * as React from 'react';
// codeblock-focus-start
import { Platform, View, Linking } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer } from '@react-navigation/native';
// codeblock-focus-end
import { Button } from '@react-navigation/elements';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Tab = createBottomTabNavigator();
const HomeStack = createNativeStackNavigator();
const SettingsStack = createNativeStackNavigator();

function A() {
return <View />;
}

function B({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('C')}>Go to C</Button>
</View>
);
}

function C({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('D')}>Go to D</Button>
</View>
);
}

function D() {
return <View />;
}

function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="A" component={A} />
</HomeStack.Navigator>
);
}

function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="B" component={B} />
<SettingsStack.Screen name="C" component={C} />
<SettingsStack.Screen name="D" component={D} />
</SettingsStack.Navigator>
);
}

// codeblock-focus-start

const PERSISTENCE_KEY = 'NAVIGATION_STATE_V1';

Expand Down Expand Up @@ -66,12 +248,27 @@ export default function App() {
AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
}
>
{/* ... */}
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{ tabBarLabel: 'Home!' }}
/>
<Tab.Screen
name="Settings"
component={SettingsStackScreen}
options={{ tabBarLabel: 'Settings!' }}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
// codeblock-focus-end
```

</TabItem>
</Tabs>

### Development Mode

This feature is particularly useful in development mode. You can enable it selectively using the following approach:
Expand Down