就绪后从 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(...),[...]);
...
}
我有一个复杂的导航器层次结构。但我会专注于问题:
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(...),[...]);
...
}