状态持久化
你可能希望在应用中保存用户的位置,以便在应用重新启动后他们立即返回到同一位置。
¥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.
用法
¥Usage
为了能够持久化 导航状态,我们可以使用容器的 onStateChange
和 initialState
属性。
¥To be able to persist the navigation state, we can use the onStateChange
and initialState
props of the container.
-
onStateChange
- 该属性会通知我们任何状态变化。我们可以在这个回调中保留状态。¥
onStateChange
- This prop notifies us of any state changes. We can persist the state in this callback. -
initialState
- 该属性允许我们传递用于 导航状态 的初始状态。我们可以在这个 prop 中传递恢复的状态。¥
initialState
- This prop allows us to pass an initial state to use for navigation state. We can pass the restored state in this prop.
- Static
- Dynamic
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>
);
}
建议在你的应用中使用 错误边界,并在发生错误时清除持久状态。这将确保如果屏幕崩溃,应用不会卡在错误状态。
¥It is recommended to use an error boundary in your app and clear the persisted state if an error occurs. This will ensure that the app doesn't get stuck in an error state if a screen crashes.
开发模式
¥Development Mode
此功能在开发模式下特别有用。你可以使用以下方法有选择地启用它:
¥This feature is particularly useful in development mode. You can enable it selectively using the following approach:
const [isReady, setIsReady] = React.useState(__DEV__ ? false : true);
虽然它也可以用于生产,但请谨慎使用,因为如果应用在特定屏幕上崩溃,它可能会导致应用无法使用 - 因为重新启动后用户仍将在同一屏幕上。因此,如果你在生产中使用它,请确保在发生错误时清除持久状态。
¥While it can be used for production as well, use it with caution as it can make the app unusable if the app is crashing on a particular screen - as the user will still be on the same screen after restarting. So if you are using it in production, make sure to clear the persisted state if an error occurs.
加载视图
¥Loading View
由于状态是异步恢复的,因此应用必须在获得初始状态之前渲染一个空/正在加载视图一段时间。为了解决这个问题,我们可以在 isReady
是 false
时返回一个加载视图:
¥Because the state is restored asynchronously, the app must render an empty/loading view for a moment before we have the initial state. To handle this, we can return a loading view when isReady
is false
:
if (!isReady) {
return <ActivityIndicator />;
}
警告:可串行化状态
¥Warning: Serializable State
每个参数、路由和导航状态都必须完全可序列化,此功能才能发挥作用。通常,你会将状态序列化为 JSON 字符串。这意味着你的路由和参数不得包含任何函数、类实例或递归数据结构。如果 React Navigation 遇到不可序列化的数据,它已经是 在开发过程中警告你,所以如果你打算保留导航状态,请注意警告。
¥Each param, route, and navigation state must be fully serializable for this feature to work. Typically, you would serialize the state as a JSON string. This means that your routes and params must contain no functions, class instances, or recursive data structures. React Navigation already warns you during development if it encounters non-serializable data, so watch out for the warning if you plan to persist navigation state.
你可以在将初始状态对象传递到容器之前对其进行修改,但请注意,如果你的 initialState
不是 有效的导航状态,React Navigation 可能无法正常处理这种情况。
¥You can modify the initial state object before passing it to container, but note that if your initialState
isn't a valid navigation state, React Navigation may not be able to handle the situation gracefully.