如何在React Native的useContext自定义hook中获取navigation导航属性
解决方案
问题根源
你无法在CommonProvider中直接使用导航方法的核心原因是自定义Provider的层级在导航容器上层:React Context仅支持自上而下传递,上层组件无法访问下层组件的Context值,所以直接调用useNavigation会抛出找不到导航上下文的错误。另外你当前hook/index.tsx中存在未匹配的</NavigationProvider>闭合标签,属于语法错误,调整时可先删除。
方案1:调整组件层级(推荐,符合React设计规范)
将所有需要使用导航能力的自定义Provider放到NavigationContainer内部,即可直接获取导航上下文:
第一步:修改hook/index.tsx的AppProvider结构
import React, { ReactNode } from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { AuthProvider } from './auth'; import { CommonProvider } from './common'; interface AppProviderProps { children: ReactNode; } function AppProvider({ children }: AppProviderProps) { return ( {/* 导航容器放在最外层 */} <NavigationContainer> <CommonProvider> <AuthProvider> {children} </AuthProvider> </CommonProvider> </NavigationContainer> ); } export { AppProvider };
第二步:在CommonProvider中获取导航对象
直接通过NavigationContext获取导航实例即可,比useNavigation更适配Provider场景:
import React, { createContext, ReactNode, useContext, useState } from 'react'; import { Dispatch, SetStateAction } from 'react'; // 导入导航上下文 import { NavigationContext } from '@react-navigation/native'; type CommonContextData = { isLoading: boolean; setIsLoading: Dispatch<SetStateAction<boolean>>; }; interface CommonProviderProps { children: ReactNode; } const CommonContext = createContext<CommonContextData>({} as CommonContextData); function CommonProvider({ children }: CommonProviderProps) { const [isLoading, setIsLoading] = useState<boolean>(false); // 直接获取导航上下文 const navigation = useContext(NavigationContext); // 测试调用导航方法 const testNavigate = () => { navigation?.navigate('TargetScreen'); } return ( <CommonContext.Provider value={{ isLoading, setIsLoading }}> {children} </CommonContext.Provider> ); } function useCommon(): CommonContextData { const context = useContext(CommonContext); return context; } export { CommonProvider, useCommon };
方案2:全局导航Ref(无需调整层级)
如果不想改动现有层级结构,可以通过全局绑定导航容器Ref的方式,在任意位置调用导航方法:
第一步:创建全局导航Ref文件src/utils/navigationRef.ts
import { createNavigationContainerRef, NavigationProp } from '@react-navigation/native'; // 替换为你自己的路由参数类型定义 type RootParamList = { Home: undefined; Login: undefined; // 其余路由自行补充 }; export const navigationRef = createNavigationContainerRef<NavigationProp<RootParamList>>(); // 封装通用跳转方法 export function navigate<T extends keyof RootParamList>(name: T, params?: RootParamList[T]) { if (navigationRef.isReady()) { navigationRef.navigate(name, params); } }
第二步:将Ref绑定到导航容器
修改hook/index.tsx中的AppProvider:
import { navigationRef } from '@/utils/navigationRef'; function AppProvider({ children }: AppProviderProps) { return ( <NavigationContainer ref={navigationRef}> <CommonProvider> <AuthProvider> {children} </AuthProvider> </CommonProvider> </NavigationContainer> ); }
第三步:在CommonProvider中直接调用导航方法
import { navigate } from '@/utils/navigationRef'; function CommonProvider({ children }: CommonProviderProps) { const [isLoading, setIsLoading] = useState<boolean>(false); // 直接调用封装好的跳转方法即可 const testNavigate = () => { navigate('Login'); } // 其余逻辑保持不变 }
内容的提问来源于stack exchange,提问作者Andersonfrfilho
相关产品推荐
相关产品推荐

