# 导航的生命周期

在前一节中,我们使用了一个堆栈导航器,它有两个屏幕(HomeDetails),并学习了如何使用 navigation.navigate('RouteName')在路由之间导航。

在这种情况下,一个重要的问题是:当我们离开它时,或者当我们回到它时,Home 会发生什么? 路由如何发现用户是离开它还是返回它?

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

# 示例场景

考虑一个带有屏幕 AB 的堆栈导航器。导航到 A 后,调用它的 componentDidMount。当 pushB 时,它的 componentDidMount 也会被调用,但是 A 仍然挂载在堆栈上,因此它的 componentWillUnmount 不会被调用。

当从 B 返回到 A 时,BcomponentWillUnmount 被调用,但 AcomponentDidMount 没有被调用,因为 A 一直保持挂载。

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

function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="First">
          {() => (
            <SettingsStack.Navigator>
              <SettingsStack.Screen
                name="Settings"
                component={SettingsScreen}
              />
              <SettingsStack.Screen name="Profile" component={ProfileScreen} />
            </SettingsStack.Navigator>
          )}
        </Tab.Screen>
        <Tab.Screen name="Second">
          {() => (
            <HomeStack.Navigator>
              <HomeStack.Screen name="Home" component={HomeScreen} />
              <HomeStack.Screen name="Details" component={DetailsScreen} />
            </HomeStack.Navigator>
          )}
        </Tab.Screen>
      </Tab.Navigator>
    </NavigationContainer>
  );
}

我们从 HomeScreen 导航到 DetailsScreen。然后我们使用标签栏切换到设置屏幕,并导航到 ProfileScreen。在这一系列操作完成后,所有 4 个屏幕都被安装了!如果你使用标签栏切换回 HomeStack,你会注意到你会看到 DetailsScreen - HomeStack 的导航状态被保留了!

# React Navigation 生命周期事件

现在我们已经理解了 React 生命周期方法在 React Navigation 中的作用,让我们来回答我们在开始时提出的问题:“我们如何发现用户是离开(blur)它还是回到它(focus)?”

React Navigation 将事件发送到订阅这些事件的屏幕组件。我们可以通过收听focusblur事件来分别知道屏幕何时聚焦或失去聚焦。

栗子:

function Profile({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener("focus", () => {
      // Screen was focused
      // Do something
    });

    return unsubscribe;
  }, [navigation]);

  return <ProfileContent />;
}

有关可用事件和 API 使用的更多细节,请参见导航事件 (opens new window)

我们可以使用 useFocusEffect (opens new window) 钩子来执行副作用,而不是手动添加事件监听器。它类似于 React 的 useEffect 钩子,但它与导航生命周期相关联。

栗子:

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

function Profile() {
  useFocusEffect(
    React.useCallback(() => {
      // Do something when the screen is focused

      return () => {
        // Do something when the screen is unfocused
        // Useful for cleanup functions
      };
    }, [])
  );

  return <ProfileContent />;
}

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

# 总结

  • 当 React 的生命周期方法仍然有效时,React Navigation 添加了更多的事件,你可以通过 navigation 属性订阅。
  • 你也可以使用 useFocusEffectuseIsFocused 钩子。