React应用中间层服务类如何编程导航至自定义错误页面?
在React Router v6的工具函数中处理重定向
首先明确:直接在非组件的工具函数里调用useNavigate或redirect是行不通的,原因如下:
useNavigate是React Hook,必须在组件或自定义Hook的顶层调用,不能在异步回调、普通函数中使用;redirect是React Router专为路由的loader/action设计的API,它会抛出一个路由响应对象,只有路由系统能捕获并处理,普通异步函数里调用不会触发跳转。
下面是几种可行的解决方案:
方案1:将navigate函数作为参数传入工具方法
这是最直接的实现方式,组件中通过useNavigate拿到导航函数,传递给sendLoginRequest,在错误回调中直接调用:
修改sendLoginRequest:
import { NavigateFunction } from "react-router-dom"; export const sendLoginRequest = async ( email: string, password: string, navigate: NavigateFunction // 新增参数 ): Promise<string> => { return axiosApiUnauthorized.post(_getLoginEndpoint(), { email, password }) .then(resp => resp.data.token) .catch(err => { console.log('err'); navigate('/error'); // 直接调用导航 throw err; // 抛出错误,让组件侧可以处理后续逻辑 }); };
在Login组件中调用:
import { useNavigate } from "react-router-dom"; const Login = () => { const navigate = useNavigate(); // 获取navigate函数 const onSubmitForm = async (formValue: any) => { try { const accessToken: string = await sendLoginRequest( formValue.email, formValue.password, navigate // 传入navigate ); storeToken('/', 'access_token', accessToken); const userInfo: UserInfo = fetchUserInfo(); dispatch(userInfoAction.saveUserInfo(userInfo)); navigate('/'); } catch (err) { // 可选:组件侧额外处理错误 } }; // ... 其他组件逻辑 };
方案2:创建全局导航工具(基于Context)
如果不想每次调用都传递navigate,可以通过React Context把导航函数全局共享:
1. 创建导航Context:
// src/context/NavigationContext.tsx import { createContext, useContext, useNavigate, NavigateFunction } from "react-router-dom"; const NavigationContext = createContext<NavigateFunction | undefined>(undefined); export const NavigationProvider = ({ children }: { children: React.ReactNode }) => { const navigate = useNavigate(); return ( <NavigationContext.Provider value={navigate}> {children} </NavigationContext.Provider> ); }; // 自定义Hook,用于获取导航函数 export const useNavigation = () => { const navigate = useContext(NavigationContext); if (!navigate) { throw new Error('useNavigation must be used within a NavigationProvider'); } return navigate; };
2. 在App根组件中包裹Provider:
// src/App.tsx import { NavigationProvider } from './context/NavigationContext'; import { RouterProvider, createBrowserRouter } from 'react-router-dom'; const router = createBrowserRouter([/* 路由配置 */]); function App() { return ( <NavigationProvider> <RouterProvider router={router} /> </NavigationProvider> ); }
3. 在工具函数中使用(需在React组件树调用链中):
// 用自定义Hook包装请求逻辑 import { useNavigation } from './context/NavigationContext'; export const useLoginRequest = () => { const navigate = useNavigation(); const sendLoginRequest = async (email: string, password: string): Promise<string> => { return axiosApiUnauthorized.post(_getLoginEndpoint(), { email, password }) .then(resp => resp.data.token) .catch(err => { console.log('err'); navigate('/error'); throw err; }); }; return { sendLoginRequest }; };
在Login组件中使用:
const Login = () => { const { sendLoginRequest } = useLoginRequest(); const onSubmitForm = async (formValue: any) => { try { const accessToken = await sendLoginRequest(formValue.email, formValue.password); // ... 后续逻辑 } catch (err) { // 错误处理 } }; };
方案3:使用Router实例的导航方法(无上下文依赖)
如果项目用createBrowserRouter创建路由,可以直接拿到router实例,调用其navigate方法,这种方式可在任何地方(包括纯工具函数)使用:
1. 定义全局Router实例:
// src/router.ts import { createBrowserRouter } from 'react-router-dom'; export const router = createBrowserRouter([ // 你的路由配置 ]);
2. 在工具函数中直接使用:
import { router } from './router'; export const sendLoginRequest = async (email: string, password: string): Promise<string> => { return axiosApiUnauthorized.post(_getLoginEndpoint(), { email, password }) .then(resp => resp.data.token) .catch(err => { console.log('err'); router.navigate('/error'); // 直接调用router的navigate throw err; }); };
内容的提问来源于stack exchange,提问作者user3457182
相关产品推荐
相关产品推荐

