状态持久化
您可能希望保存用户在应用中的位置,以便在应用重启后立即返回到相同的位置。
这在开发过程中尤其有价值,因为它允许开发者在刷新应用时保持在相同的屏幕上。
用法
为了能够持久化导航状态,我们可以使用容器的 onStateChange
和 initialState
属性。
onStateChange
- 此属性通知我们任何状态更改。我们可以在此回调中持久化状态。initialState
- 此属性允许我们传递一个初始状态以用于导航状态。我们可以在此属性中传递恢复的状态。
- 静态
- 动态
import { Platform, View, Linking } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
useNavigation,
createStaticNavigation,
} from '@react-navigation/native';
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))
}
/>
);
}
import { Platform, View, Linking } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
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 (initialUrl == null) {
// Only restore state if there's no deep link
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 null;
}
return (
<NavigationContainer
initialState={initialState}
onStateChange={(state) =>
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>
);
}
警告
建议在您的应用中使用错误边界,并在发生错误时清除持久化状态。这将确保应用在屏幕崩溃时不会卡在错误状态。
开发模式
此功能在开发模式下尤其有用。您可以使用以下方法选择性地启用它
const [isReady, setIsReady] = React.useState(__DEV__ ? false : true);
虽然它也可以用于生产环境,但请谨慎使用,因为它可能会使应用变得不可用,如果应用在特定屏幕上崩溃 - 因为用户在重启后仍然会在相同的屏幕上。因此,如果您在生产环境中使用它,请确保在发生错误时清除持久化状态。
加载视图
由于状态是异步恢复的,因此应用必须在获得初始状态之前渲染一个空/加载视图片刻。为了处理这个问题,我们可以在 isReady
为 false
时返回一个加载视图
if (!isReady) {
return <ActivityIndicator />;
}
警告:可序列化状态
为了使此功能正常工作,每个参数、路由和导航状态都必须完全可序列化。通常,您会将状态序列化为 JSON 字符串。这意味着您的路由和参数不能包含函数、类实例或递归数据结构。如果 React Navigation 在开发过程中遇到不可序列化的数据,它已经会警告您,因此如果您计划持久化导航状态,请注意此警告。
您可以在将初始状态对象传递给容器之前对其进行修改,但请注意,如果您的 initialState
不是有效的导航状态,React Navigation 可能无法优雅地处理这种情况。