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 钩子,但它与导航生命周期相关。

¥For performing side effects, we can use the useFocusEffect hook instead of subscribing to events. 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.

如果你想在事件监听器中了解屏幕是否获得焦点,可以使用 navigation.isFocused() 方法。请注意,使用此方法不会像 useIsFocused hook 那样触发重新渲染,因此它不适用于根据焦点状态渲染不同的内容。

¥If you want to know if the screen is focused or not inside of an event listener, you can use the navigation.isFocused() method. Note that using this method doesn't trigger a re-render like the useIsFocused hook does, so it is not suitable for rendering different things based on focus state.

概括

¥Summary

  • React Navigation 在离开当前屏幕时不会卸载该屏幕。

    ¥React Navigation does not unmount screens when navigating away from them

  • useFocusEffect hook 类似于 React 的 useEffect,但它与导航生命周期绑定,而不是组件生命周期。

    ¥The useFocusEffect hook is analogous to React's useEffect but is tied to the navigation lifecycle instead of the component lifecycle.

  • useIsFocused hook 和 navigation.isFocused() 方法可用于确定当前屏幕是否处于焦点状态。

    ¥The useIsFocused hook and navigation.isFocused() method can be used to determine if a screen is currently focused.

  • React Navigation 会发出 focusblur 事件,你可以在屏幕获得焦点或失去焦点时监听这些事件。

    ¥React Navigation emits focus and blur events that can be listened to when a screen comes into focus or goes out of focus.