通过react-router-dom6的loader实现菜单权限和登录拦截。
react-router-dom中route介绍:
const router = createBrowserRouter([{// it renders this elementelement: ,// when the URL matches this segmentpath: "teams/:teamId",// with this data loaded before renderingloader: async ({ request, params }) => {return fetch(`/fake/api/teams/${params.teamId}.json`,{ signal: request.signal });},// performing this mutation when data is submitted to itaction: async ({ request }) => {return updateFakeTeam(await request.formData());},// and renders this element in case something went wrongerrorElement: ,},
]);//或组件版
const router = createBrowserRouter(createRoutesFromElements( }path="teams/:teamId"loader={async ({ params }) => {return fetch(`/fake/api/teams/${params.teamId}.json`);}}action={async ({ request }) => {return updateFakeTeam(await request.formData());}}errorElement={ }/>)
);
渲染内容为element,当渲染出错会渲染errorElement(该组件中通过hook:useRouteError可以获取到错误信息,之后ui显示处理),path为*匹配任何路由用来兜底
createBrowserRouter([{path: "/",loader: () => fetchUser(),element: ,id: "root",children: [{path: "jobs/:jobId",loader: loadJob,element: ,},],},
]);const user = useRouteLoaderData("root");
import { useActionData, Form } from "react-router-dom";export default function Login() {//页面初次渲染,获取为空 并不会触发上面的action submit后才会触发const errors = useActionData();return ();
}export async function loginAction({ request }) {const formData = await request.formData();const email = formData.get("email");const password = formData.get("password");const errors = {};// validate the fieldsif (typeof email !== "string" || !email.includes("@")) {errors.email ="That doesn't look like an email address";}if (typeof password !== "string" || password.length < 6) {errors.password = "Password must be > 6 characters";}// return data if we have errorsif (Object.keys(errors).length) {return errors;}// otherwise create the user and redirectawait createUser(email, password);return redirect("/dashboard");
}
loader和action中可以使用redirect跳转,注意redirect跳转 前面加上return,loader和action要求必须有return,不跳转并直接导致loader/action报错,redirect不在其他地方使用,其他地方用navigate/useNavigate实现重定向
使用loader去获取用户权限信息,组件上包裹一层权限组件,里面获取loader中获取的权限信息,之后判断要显示的组件是否在权限内。
import { lazy, Suspense } from "react";
import { createBrowserRouter, Navigate, redirect } from "react-router-dom";
import type { RouteObject } from "react-router-dom";
import ErrorBoundary from "../components/ErrorBoundary";// 不需要懒加载的页面组件
import Layout from "../pages/Layout";
import Permission from "../components/Permission";
import NotFound from "../container/NotFound";// 需要懒加载的页面组件
const Home = lazy(() => import("../container/Home"));
const About = lazy(() => import("../container/About"));
const Setting = lazy(() => import("../container/Setting"));
const Login = lazy(() => import("../container/Login"));/*** @param Component 懒加载的组件* @param code 用于判断权限的字段(你可以自己定)* @returns*/
const LazyLoad = (Component: React.LazyExoticComponent<() => JSX.Element>,code?: string
) => {return (loading...
Permission组件:
import { FC, PropsWithChildren } from "react";
import { useRouteLoaderData } from "react-router-dom";
import type { UserInfo } from "../routers";interface Iprops {code?: string;
}const Permission: FC> = (props) => {// 这个root是我们在前面路由中定义了 id: 'root'const loaderData = useRouteLoaderData("root") as UserInfo;const { children, code } = props;if (!code || loaderData?.permissionRoutes?.includes(code)) {return <>{children}>;}return 403...;
};export default Permission;
ErrorBoundary组件:
import { useRouteError } from "react-router-dom";const ErrorBoundary = () => {const err = useRouteError() as any;return (出错啦~
错误信息: {err.message}
);
};export default ErrorBoundary;
Layout组件:Outlet用于渲染子组件内容,路由配置时不设置path而是添加index则代表时默认路由
import { Outlet, useLoaderData } from "react-router-dom";function Layout() {const data = useLoaderData();return (welcome {data.name} 年龄:{data.age}
);
}export default Layout;
loader在组件渲染前加载数据,可以防止页面先进去之后数据返回来在判断权限不符合跳转兜底页要好,类似于vue-router的router.beforeEach在页面跳转前判断是否有权限跳转
其他:借助于react自定义hook+context实现
React-Router v6 实现登录验证流程 - 掘金
react-router v6路由拦截/路由守卫/路由鉴权_#Undefined的博客-CSDN博客_react路由拦截和路由守卫