跳到主要内容
版本:7.x

导航生命周期

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

在这种情况下,一个重要的问题是:当我们离开 Home 屏幕或返回到它时,Home 屏幕会发生什么?屏幕如何知道用户正在离开它或返回到它?

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

示例场景

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

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

与其他导航器(组合使用)也可以观察到类似的结果。考虑一个带有两个标签的标签导航器,其中每个标签都是一个堆栈导航器

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,
},
});
Snack 上尝试

我们从 HomeScreen 开始导航到 DetailsScreen。然后我们使用标签栏切换到 SettingsScreen 并导航到 ProfileScreen。在此操作序列完成后,所有 4 个屏幕都已挂载!如果您使用标签栏切换回 HomeStack,您会注意到您将看到 DetailsScreen - HomeStack 的导航状态已保留!

React Navigation 生命周期事件

现在我们了解了 React 生命周期方法在 React Navigation 中的工作方式,让我们回答我们在开始时提出的问题:“我们如何知道用户正在离开(blur)它或返回到它(focus)?”

React Navigation 向订阅它们的屏幕组件发出事件。我们可以监听 focusblur 事件,以了解屏幕何时进入焦点或失去焦点。

示例

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>
);
}
Snack 上尝试

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

除了手动添加事件监听器之外,我们可以使用 useFocusEffect Hook 来执行副作用。它类似于 React 的 useEffect Hook,但它与导航生命周期相关联。

示例

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>
);
}
Snack 上尝试

如果您想根据屏幕是否聚焦来渲染不同的内容,则可以使用 useIsFocused Hook,它返回一个布尔值,指示屏幕是否聚焦。

总结

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