就绪后从 navigator/parent 组件导航

Navigate from the navigator/parent component when it is ready

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

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

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

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

现在我明白这是什么问题了!当应用程序从退出状态重新加载时,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>
  );
}

您可以在 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>
  );
}

经过大量尝试后,我将所有导航功能移至我的自定义选项卡视图渲染器(我使用 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)
}

您可以将 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(...),[...]);
   ...
}