React路由react-router-dom鉴权以及网页标题

开源地址:GitHub - remix-run/react-router: Declarative routing for React

react 路由有三种写法:传统组件法、useRoutes 法、data Router 法

  • 官方推荐的写法是 data Router
  • 这里用 data Router
  • route 的 handle 类似 vue-router 中的 meta
  • handle 属性仅在 data Router 下有效
  • 获取 handle 的 useMatches 只能在 data Router 下调用
// routes.tsx
import { createBrowserRouter, Navigate } from "react-router-dom";
import { PageIndex } from "@/page";
export const router = createBrowserRouter([
  {
    // 确保所有的路由都走 AuthRoute 组件
    path: "/",
    // 这个组件做鉴权和处理标题
    element: <AuthRoute />,
    // 真正的网页
    children: [
      { path: "", element: <PageIndex />, handle: { title: "首页" } },
      { path: "login", element: <PageLogin />, handle: { title: "登录页" } },
      // 没有匹配到的路由重定向到 404
      { path: "*", element: <Navigate to="404" replace /> },
      { path: "404", element: <Page404 />, handle: { title: "404页" } },
    ],
  },
]);
// App.jsx
import { RouterPrivider } from "react-router-dom";
import { router } from "./routes";
export function App() {
  return <RouterProvider router={router} />;
}

鉴权 & 网页标题

  1. 所有路由变化都会触发 AuthRoute 的更新
  2. AuthRoute 返回的 JSX 就是路由的结果
// route/index.ts
/**
 * 实现路由鉴权,并根据路由修改网页标题
 * @returns 通过时为 page,反之 PageLogin
 */
function AuthRoute() {
  /**
   * 1.获取路由匹配信息
   * 2.获取子路由元素
   * 3.获取 store 中的登录信息
   */
  const matches = useMatches(); //这个钩子只有 data Router 下能用
  const outlet = useOutlet();
  const isLogined = useAppSelector((state) => state.auth.isLogined);
  /**
   * 当前路径是否在白名单?
   * 当前是否已登录?
   * 都不是则重向定到 PageLogin
   */
  const page = useMemo(() => {
    const { pathname } = matches[1];
    const isInWL = whiteList.includes(pathname);
    if (isInWL) return outlet;
    if (isLogined) return outlet;
    return <Navigate to="login" replace />;
  }, [isLogined, matches, outlet]);
  /**
   * 模仿 vue-router 后置钩子修改网页标题
   */
  useEffect(() => {
    const title = (matches[1].handle as any)?.title;
    const isHasTitle = typeof title === "string";
    if (isHasTitle) {
      document.title = title;
    }
  }, [matches]);
  return page;
}

懒加载

  1. vue-router 里的 component 可以直接写成一个回调实现懒加载
  2. 但是 react-router 没有,需要我们自己写 hook
// useLazy.tsx
import { Skeleton } from "antd";
import React from "react";
/**
 * @function useResize 使用的类型
 */
export namespace Type {
  export type defRC = {
    default: React.ComponentType<any>;
  };
}
/**
 * 类似 React.lazy,实现组件懒加载
 * @param callback 返回 Promise 的函数
 * @returns JSX
 */
export function useLazy(callback: () => Promise<Type.defRC>) {
  const LazyComp = React.lazy(callback);
  return (
    <React.Suspense fallback={<Skeleton active />}>
      <LazyComp />
    </React.Suspense>
  );
}

用上 hook 后,route 的写法:

// routes.tsx
import { Navigate, RouteObject } from "react-router-dom";
export const routes: RouteObject[] = [
  {
    path: "/home",
    element: useLazy(() => import("@/page/home")),
  },
];

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1024小神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值