在Gorhom底部弹窗中使用React Navigation向Tab栈推送路由问题
问题描述
在React Native应用中,使用React Navigation处理路由、Gorhom Bottom Sheet实现底部弹窗交互,当前配置如下:
NavigationWrapper.tsx
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { NavigationContainer } from "@react-navigation/native"; import { PLScreenRoute } from "navigation/screenRoutes"; import FeedTab from "navigation/tabs/feed/FeedTab"; import { BottomSheetModalProvider } from "@gorhom/bottom-sheet"; type NavigationWrapperProps = { setAppIsReady: () => void; }; const NavigationWrapper = ({ setAppIsReady }: NavigationWrapperProps) => { const Tab = createBottomTabNavigator(); return ( <NavigationContainer > {/*modal provider is here so we can do routing inside of bottom sheets*/} <BottomSheetModalProvider> <Tab.Navigator > <Tab.Screen name={PLScreenRoute.FEED_ROOT} component={FeedTab} /> </Tab.Navigator> </BottomSheetModalProvider> </NavigationContainer> ); }; export default NavigationWrapper;
FeedTab示例代码
import { PLScreenRoute } from "navigation/screenRoutes"; import FeedScreen from "screens/feed/feed/FeedScreen"; import FeedHeader from "screens/feed/feed/FeedHeader"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; export const FeedTabStack = createNativeStackNavigator(); const FeedTab = () => { return ( <FeedTabStack.Navigator initialRouteName={PLScreenRoute.FEED}> <FeedTabStack.Screen name={PLScreenRoute.FEED} component={FeedScreen} options={{ header: () => <FeedHeader />, }} /> </FeedTabStack.Navigator> ); }; export default FeedTab;
问题详情
在底部弹窗外调用以下代码正常:
import { useNavigation } from "@react-navigation/native"; import { PLScreenRoute } from "navigation/screenRoutes"; const navigator = useNavigation(); const navigate = () => navigator.push(PLScreenRoute.FEED)
但在底部弹窗内调用会崩溃,报错:TypeError: navigator.push is not a function (it is undefined), js engine: hermes
改用navigator.navigate()可正常工作,但需要push()的重复入栈功能,而非navigate()的路由切换逻辑(若路由已存在则直接切换到对应栈)。
解决方案
原因分析
底部弹窗内通过useNavigation()获取的是TabNavigator的导航器实例,而Tab导航器本身没有push()方法,只有navigate();弹窗之外的组件处于StackNavigator的上下文内,拿到的是Stack导航器实例,因此push()可用。
具体解决方法
方法1:明确指定Stack导航器类型
在FeedTab文件中定义栈导航器的类型,然后在弹窗组件中通过泛型获取对应导航器:
- 在FeedTab.tsx中添加类型定义:
// FeedTab.tsx import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { PLScreenRoute } from "navigation/screenRoutes"; // 定义FeedTab栈的导航类型 export type FeedTabNavigationProp = NativeStackNavigationProp< typeof FeedTabStack.navigator, PLScreenRoute.FEED >;
- 在弹窗组件中使用泛型版
useNavigation():
import { useNavigation } from "@react-navigation/native"; import { FeedTabNavigationProp } from "navigation/tabs/feed/FeedTab"; import { PLScreenRoute } from "navigation/screenRoutes"; const navigator = useNavigation<FeedTabNavigationProp>(); const navigate = () => navigator.push(PLScreenRoute.FEED);
方法2:调整BottomSheetModalProvider层级
将BottomSheetModalProvider从TabNavigator外层移到每个Tab的StackNavigator内部,让弹窗处于Stack导航器的上下文:
- 修改NavigationWrapper.tsx:
// NavigationWrapper.tsx import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { NavigationContainer } from "@react-navigation/native"; import { PLScreenRoute } from "navigation/screenRoutes"; import FeedTab from "navigation/tabs/feed/FeedTab"; type NavigationWrapperProps = { setAppIsReady: () => void; }; const NavigationWrapper = ({ setAppIsReady }: NavigationWrapperProps) => { const Tab = createBottomTabNavigator(); return ( <NavigationContainer> <Tab.Navigator> <Tab.Screen name={PLScreenRoute.FEED_ROOT} component={FeedTab} /> </Tab.Navigator> </NavigationContainer> ); }; export default NavigationWrapper;
- 修改FeedTab.tsx,将Provider包裹StackNavigator:
// FeedTab.tsx import { PLScreenRoute } from "navigation/screenRoutes"; import FeedScreen from "screens/feed/feed/FeedScreen"; import FeedHeader from "screens/feed/feed/FeedHeader"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import { BottomSheetModalProvider } from "@gorhom/bottom-sheet"; export const FeedTabStack = createNativeStackNavigator(); const FeedTab = () => { return ( <BottomSheetModalProvider> <FeedTabStack.Navigator initialRouteName={PLScreenRoute.FEED}> <FeedTabStack.Screen name={PLScreenRoute.FEED} component={FeedScreen} options={{ header: () => <FeedHeader />, }} /> </FeedTabStack.Navigator> </BottomSheetModalProvider> ); }; export default FeedTab;
方法3:通过getParent()获取Stack导航器(不推荐)
若不想调整组件层级,可尝试从Tab导航器获取父级Stack导航器,但该方式依赖路由层级结构,后续变更易出问题:
import { useNavigation } from "@react-navigation/native"; import { FeedTabNavigationProp } from "navigation/tabs/feed/FeedTab"; import { PLScreenRoute } from "navigation/screenRoutes"; const navigator = useNavigation(); const stackNavigator = navigator.getParent<FeedTabNavigationProp>(); const navigate = () => stackNavigator?.push(PLScreenRoute.FEED);
内容的提问来源于stack exchange,提问作者Malice
相关产品推荐
相关产品推荐

