Skip to main content
Version: 7.x

导航生命周期

在上一节中,我们使用了一个具有两个屏幕(HomeProfile)的堆栈导航器,并学习了如何使用 navigation.navigate('RouteName') 在屏幕之间导航。

¥In a previous section, we worked with a stack navigator that has two screens (Home and Profile) and learned how to use navigation.navigate('RouteName') to navigate between the screens.

在这方面的一个重要问题是:当我们离开或回到 Home 时,会发生什么?屏幕如何发现用户正在离开或返回?

¥An important question in this context is: what happens with Home when we navigate away from it, or when we come back to it? How does a screen find out that a user is leaving it or coming back to it?

如果你从 Web 背景进入 react-navigation,你可能会假设当用户从路由 A 导航到路由 B 时,A 将卸载(其 componentWillUnmount 被调用),并且当用户返回时 A 将再次挂载。虽然这些 React 生命周期方法仍然有效并在 React Navigation 中使用,但它们的用法与 Web 不同。这是由更复杂的移动导航需求驱动的。

¥If you are coming to react-navigation from a web background, you may assume that when the user navigates from route A to route B, A will unmount (its componentWillUnmount is called) and A will mount again when the user comes back to it. While these React lifecycle methods are still valid and are used in React Navigation, their usage differs from the web. This is driven by the more complex needs of mobile navigation.

示例场景

¥Example scenario

考虑一个具有 2 个屏幕的堆栈导航器:HomeProfile。当我们首次渲染导航器时,Home 屏幕已安装,即调用其 useEffectcomponentDidMount。当我们导航到 Profile 时,现在 Profile 已安装,并调用其 useEffectcomponentDidMount。但 Home 什么也没发生 - 它仍然挂载在堆栈中。不调用 useEffectcomponentWillUnmount 返回的清理函数。

¥Consider a stack navigator with 2 screens: Home and Profile. When we first render the navigator, the Home screen is mounted, i.e. its useEffect or componentDidMount is called. When we navigate to Profile, now Profile is mounted and its useEffect or componentDidMount is called. But nothing happens to Home - it remains mounted in the stack. The cleanup function returned by useEffect or componentWillUnmount is not called.

当我们从 Profile 返回到 Home 时,Profile 已卸载,并调用其 useEffect 清理或 componentWillUnmount。但 Home 未再次安装 - 它一直保持挂载状态 - 并且不调用其 useEffectcomponentDidMount

¥When we go back from Profile to Home, Profile is unmounted and its useEffect cleanup or componentWillUnmount is called. But Home is not mounted again - it remained mounted the whole time - and its useEffect or componentDidMount is not called.

与其他导航器(结合)也可以观察到类似的结果。考虑一个带有两个选项卡的选项卡导航器,其中每个选项卡都是一个堆栈导航器:

¥Similar results can be observed (in combination) with other navigators as well. Consider a tab navigator with two tabs, where each tab is a stack navigator:

const SettingsStack = createNativeStackNavigator({
screens: {
Settings: SettingsScreen,
Profile: ProfileScreen,
},
});

const HomeStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
Details: DetailsScreen,
},
});

const MyTabs = createBottomTabNavigator({
screenOptions: {
headerShown: false,
},
screens: {
First: SettingsStack,
Second: HomeStack,
},
});
Try on Snack

我们从 HomeScreen 开始,导航至 DetailsScreen。然后我们使用标签栏切换到 SettingsScreen 并导航到 ProfileScreen。完成这一系列操作后,所有 4 个屏幕都安装完毕!如果你使用选项卡栏切换回 HomeStack,你会发现你将看到 DetailsScreen - HomeStack 的导航状态已保留!

¥We start on the HomeScreen and navigate to DetailsScreen. Then we use the tab bar to switch to the SettingsScreen and navigate to ProfileScreen. After this sequence of operations is done, all 4 of the screens are mounted! If you use the tab bar to switch back to the HomeStack, you'll notice you'll be presented with the DetailsScreen - the navigation state of the HomeStack has been preserved!

React 导航生命周期事件

¥React Navigation lifecycle events

现在我们了解了 React 生命周期方法在 React Navigation 中的工作原理,让我们回答一开始提出的问题:"我们如何发现用户正在离开(模糊)它或返回它(焦点)?"

¥Now that we understand how React lifecycle methods work in React Navigation, let's answer the question we asked at the beginning: "How do we find out that a user is leaving (blur) it or coming back to it (focus)?"

React Navigation 向订阅这些事件的屏幕组件触发事件。我们可以监听 focusblur 事件来分别了解屏幕何时进入焦点或失焦。

¥React Navigation emits events to screen components that subscribe to them. We can listen to focus and blur events to know when a screen comes into focus or goes out of focus respectively.

示例:

¥Example:

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

React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
console.log('ProfileScreen focused');
});

return unsubscribe;
}, [navigation]);

React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
console.log('ProfileScreen blurred');
});

return unsubscribe;
}, [navigation]);

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
</View>
);
}
Try on Snack

有关可用事件和 API 使用的更多详细信息,请参阅 导航事件

¥See Navigation events for more details on the available events and the API usage.

我们可以使用 useFocusEffect 钩子来执行副作用,而不是手动添加事件监听器。它就像 React 的 useEffect 钩子,但它与导航生命周期相关。

¥Instead of adding event listeners manually, we can use the useFocusEffect hook to perform side effects. It's like React's useEffect hook, but it ties into the navigation lifecycle.

示例:

¥Example:

import { useFocusEffect } from '@react-navigation/native';

function ProfileScreen() {
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused
console.log('ProfileScreen focus effect');

return () => {
// Do something when the screen is unfocused
// Useful for cleanup functions
console.log('ProfileScreen focus effect cleanup');
};
}, [])
);

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
</View>
);
}
Try on Snack

如果你想根据屏幕是否聚焦来渲染不同的东西,你可以使用 useIsFocused 钩子,它返回一个布尔值来指示屏幕是否聚焦。

¥If you want to render different things based on if the screen is focused or not, you can use the useIsFocused hook which returns a boolean indicating whether the screen is focused.

概括

¥Summary

  • 虽然 React 的生命周期方法仍然有效,但 React Navigation 添加了更多事件,你可以通过 navigation 对象订阅这些事件。

    ¥While React's lifecycle methods are still valid, React Navigation adds more events that you can subscribe to through the navigation object.

  • 你还可以使用 useFocusEffectuseIsFocused 钩子。

    ¥You may also use the useFocusEffect or useIsFocused hooks.