React共享服务中使用useNavigate触发无效Hook调用的解决方法
你遇到的错误核心原因是违反了React Hooks规则:useNavigate作为Hook,只能在函数组件的顶层或者自定义Hook的顶层调用,而你直接在普通函数Redirect中调用它,当通过COMMON.redirect('/')执行时,这个调用不在React组件的渲染上下文里,所以触发了Invalid hook call错误。
下面是两种可行的解决方案,都能实现无需重复导入useNavigate的需求:
方案一:自定义Hook(推荐)
创建一个自定义Hook,在内部封装useNavigate并导出redirect方法,这样组件调用这个Hook时,Hook的执行处于组件渲染上下文内,符合规则:
// CommonService.tsx import { useNavigate } from "react-router-dom"; export function useCommon() { const navigate = useNavigate(); // 封装redirect方法 const redirect = (route: string) => { navigate(route); }; // 可在此添加更多共享方法 return { redirect }; }
在组件中使用:
// 任意组件文件 import { useCommon } from './CommonService'; function MyComponent() { const { redirect } = useCommon(); const handleClick = () => { redirect('/'); // 正常调用 }; return <button onClick={handleClick}>返回首页</button>; }
方案二:导航上下文(适配非组件场景)
如果需要在非组件(比如工具函数、异步回调)中实现导航,可以通过React Router的导航上下文来获取导航函数:
1. 创建导航上下文与Provider
// NavigationContext.tsx import { createContext, useContext, useNavigate } from "react-router-dom"; const NavigationContext = createContext<{ redirect: (route: string) => void } | null>(null); export function NavigationProvider({ children }: { children: React.ReactNode }) { const navigate = useNavigate(); const redirect = (route: string) => { navigate(route); }; return ( <NavigationContext.Provider value={{ redirect }}> {children} </NavigationContext.Provider> ); } export function useNavigation() { const context = useContext(NavigationContext); if (!context) { throw new Error('useNavigation必须在NavigationProvider内部使用'); } return context; }
2. 在路由外层包裹Provider
// App.tsx import { BrowserRouter } from "react-router-dom"; import { NavigationProvider } from './NavigationContext'; function App() { return ( <BrowserRouter> <NavigationProvider> {/* 你的路由组件 */} </NavigationProvider> </BrowserRouter> ); }
3. 在组件/非组件中调用
// 组件中使用 import { useNavigation } from './NavigationContext'; function MyComponent() { const { redirect } = useNavigation(); // 业务逻辑中调用redirect } // 非组件工具函数(需在React组件树的回调中调用,不可直接在异步函数顶层执行) async function fetchData() { const res = await fetch('/api/data'); if (res.status === 401) { const { redirect } = useNavigation(); redirect('/login'); } }
内容的提问来源于stack exchange,提问作者redrom
相关产品推荐
相关产品推荐

