在 react router v6 中,loader 返回 `redirect()` 对象时若被误包进普通数据结构,会导致跳转失效;本文提供一种类型安全、可预测的响应封装模式,通过 `data`/`redirect` 双字段结构实现自动重定向检测与拦截。
在 React Router v6 的数据加载流程中,loader 函数必须直接返回 redirect() 调用(如 return redirect(‘/’))才能触发导航;若将 redirect() 实例作为某个对象的属性(例如 { permissions: redirect(‘/’) })返回,Router 将视其为普通数据,不会执行跳转——这正是你遇到的核心问题。
根本原因在于:redirect() 返回的是一个特殊的、具有 type: “redirect” 和 location 字段的 Plain Object(由 createRedirect 构造),它仅在 loader 顶层返回值 中才被 Router 解析为导航指令。一旦被嵌套,就失去了语义意义。
✅ 推荐解决方案:采用标准化响应契约(Response Contract)
即让所有异步请求处理器(如 responseHandler)统一返回形如 { data: T | null; redirect?: string } 的对象。该结构明确区分「有效数据」与「跳转指令」,既保持类型清晰,又便于 loader 层做集中判断。
以下是优化后的完整实践:
1. 改写 responseHandler —— 统一返回结构
const toastOptions = {
position: toast.POSITION.TOP_RIGHT,
};
export function responseHandler(response: AxiosResponse) {
// 成功且业务态 success === true
if (response.data?.success === true) {
toast.success(response.data.message, toastOptions);
return { data: response.data.data };
}
// 业务失败(success === false)
if (response.data?.success === false) {
toast.error(response.data.message, toastOptions);
return { data: null };
}
// HTTP 状态异常:401 或其他错误
if (response.status === 401) {
localStorage.clear();
toast.error(response.data?.message || 'Unauthorized', toastOptions);
} else {
toast.error('Something went wrong', toastOptions);
}
// 所有异常路径均返回重定向指令(不执行 redirect()!)
return { redirect: '/' };
}
⚠️ 关键注意:此处 绝不调用 redirect(),而是返回 { redirect: ‘/login’ } 这样的纯对象。真正的 redirect() 调用只发生在 loader 顶层。
2. 增强 loader —— 检测并透传重定向
import { redirect } from 'react-router-dom';
export async function loader({ params }: LoaderFunctionArgs) {
const { userId, userAction } = params;
// 并发请求,各自返回 { data, redirect? }
const [permissionsRes, userDetailRes] = await Promise.all([
getAllPermissions(),
loadUserDetail(userId, userAction),
]);
// 任一响应含 redirect → 立即终止加载,触发跳转
if (permissionsRes.redirect) {
return redirect(permissionsRes.redirect);
}
if (userDetailRes.redirect) {
return redirect(userDetailRes.redirect);
}
// 否则组装正常数据
return {
permissions: permissionsRes.data,
userDetail: userDetailRes.data,
userAction,
};
}
✅ 优势: