【问题标题】:Navigate from the navigator/parent component when it is ready准备好后从导航器/父组件导航
【发布时间】:2021-06-01 21:09:01
【问题描述】:

我有一个复杂的导航器层次结构。但我会专注于这个问题:

Stack navigator
-- Tab navigator
---- Home stack navigator (initial route)
---- Other screens
-- Other screens

用于导航的navigation 对象由屏幕的道具或通过在任何屏幕子组件上使用挂钩useNavigation() 提供。

我在我的应用中使用深度链接来导航几乎所有地方。我的主要根导航器容器是选项卡导航器。因此,将用户从那里路由到其他屏幕/选项卡似乎非常合乎逻辑。我使用了navigation 传递给useEffect 中的选项卡导航器的道具,它工作得很好,这让我感到惊讶,因为我在导航器(而不是屏幕)中使用它。

现在我知道这是什么问题了!当应用程序从退出状态重新加载时,navigation.navigate(...) 在这种情况下不起作用(没有抛出任何东西)。这是因为导航似乎发生在导航器被渲染之前。

我检查了this 是否有可能的解决方案,但它并没有解决我的问题,因为NavigationContainer 已准备就绪,但选项卡导航器没有。

当我在主屏幕上将导航移动到useFocusEffect 时,它工作正常。

如何验证导航器是否已完成渲染?

示例代码:

function MainTabNav({ navigation }) {
  useEffect(() => {
    console.log("trying to navigate...");
    navigation.navigate("other_screen")
  }, [navigation]);

  return (
      <Tab.Navigator
        initialRouteName={...}
      >
        ... // Stack navigators for home & other screens
      </Tab.Navigator>
  );
}

【问题讨论】:

    标签: react-native react-navigation react-navigation-v5


    【解决方案1】:

    您可以将navigationContainerRef 存储在上下文中并通过挂钩将其公开:

    const NavigationContainerContext = React.createContext();
    const useNavigationContainerRef = () => useContext(NavigationContainerContext);
    const MyNavigationContainer = () => {
      const navigationContainerRef = useRef(null);
      return (
        <NavigationContainerContext.Provider value={}>
          <NavigationContainer ref={navigationContainerRef}/>
        </NavigationContainerContext.Provider>
      );
    }
    

    然后使用另一个钩子管理导航逻辑:

    function useMyNavigation(navigation){
      const navigate = useCallback(()=>{
        const rootState = navigationContainerRef.current?.getRootState();
        if(rootState != null){
          navigation.navigate(...);
        }
      });
      return {navigate};
    }
    

    然后在屏幕的useEffect 上使用从挂钩中暴露的navigate 函数。由于您的屏幕是导航状态的一部分,因此导航状态必须准备好让您的屏幕呈现:

    const MyScreen = () => {
       const navigation = useNavigation();
       const myNavigation = useMyNavigation(navigation);
       useEffect(()=>myNavigation.navigate(...),[...]);
       ...
    }
    

    【讨论】:

      【解决方案2】:

      您可以在 nagivation.navigate() 函数之前尝试一个条件来检查是否定义了导航。

      navigation && navigation.navigate("other_screen")
      

      这只会在导航不等于 null 或 undefined 时运行。所以你的代码看起来像:

      function MainTabNav({ navigation }) {
        useEffect(() => {
          console.log("trying to navigate...");
          navigation && navigation.navigate("other_screen")
        }, [navigation]);
      
        return (
            <Tab.Navigator
              initialRouteName={...}
            >
              ... // Stack navigators for home & other screens
            </Tab.Navigator>
        );
      }
      

      【讨论】:

      • 导航对象已定义——这不是问题
      【解决方案3】:

      在玩了很多之后,我将所有导航功能移到了我的自定义选项卡视图渲染器(我使用 ui-kittens 作为 UI 框架)并触发了 onLayout - 这验证了选项卡的渲染已经完成,导航器可以从父级到子级使用。

      function MainTabNav({ navigation }) {
        useEffect(() => {
          console.log("trying to navigate...");
          navigation.navigate("other_screen")
        }, [navigation]);
      
        return (
            <Tab.Navigator
              initialRouteName={...}
              tabBar={(props) => <MyTabBar {...props} />}
            >
              ... // Stack navigators for home & other screens
            </Tab.Navigator>
        );
      }
      
      function MyTabBar(){
        ...
        return (
          <MyBar onLayout={() => doInitialNavigation()}>
            ... // tab views
          </MyBar>
        )
      }
      
      function doInitialNavigation(){
        ... // when you are here the tab navigator has loaded and you can navigate to any tab on app load (even after quit state)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-12
        • 2020-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-04
        • 2020-01-31
        相关资源
        最近更新 更多