React-Router-V6的简单使用

577 阅读1分钟

源码

源码地址

说明:

我这里是用了一个做了一个小demo,用到了antd的菜单

课前准备

创建Page目录(放页面)以及router目录(放路由以及菜单)

步骤一

我这里先搞个菜单

// src/router/routes.tsx
import { MenuProps } from "antd";
type MenuItem = Required<MenuProps>["items"][number];
​
export function getItem(
  label: React.ReactNode,
  key: React.Key,
  icon?: React.ReactNode,
  children?: MenuItem[],
  type?: "group"
): MenuItem {
  return {
    key,
    icon,
    children,
    label,
    type,
  } as MenuItem;
}
// src/router/index.tsx
import { MenuProps } from "antd";
import { MailOutlined } from "@ant-design/icons";
​
import { getItem } from "./routes";
​
export const items: MenuProps["items"] = [
  getItem("菜单", "sub1", <MailOutlined />, [
    getItem("首页", "/home"),
    getItem("关于", "/about"),
  ]),
];
// src/App.tsx
import { Menu } from "antd";
​
import { items } from "./router";
​
function App() {
  const location = useLocation();
  const navigator = useNavigate();
​
  const MenuClickHandle = (e: any) => {
    navigator(e.key);
  };
​
  return (
    <div className="App">
      <Menu
        items={items}
        selectedKeys={[`${location.pathname}`]}
        style={{ width: 256 }}
        defaultOpenKeys={["sub1"]}
        mode="inline"
        onClick={(e) => MenuClickHandle(e)}
      />
    </div>
  );
}
​
export default App;

这时候菜单已经完成了~~~~

步骤二

开始玩路由了(在原有代码基础上继续加)

先在路由文件里面定义,再到出口文件处理

// src/router/routes.tsximport { MenuProps, Spin } from "antd";
import { RouteObject } from "react-router-dom";
import { FC, lazy, LazyExoticComponent, Suspense } from "react";
​
type MenuItem = Required<MenuProps>["items"][number];
​
export function getItem(
  label: React.ReactNode,
  key: React.Key,
  icon?: React.ReactNode,
  children?: MenuItem[],
  type?: "group"
): MenuItem {
  return {
    key,
    icon,
    children,
    label,
    type,
  } as MenuItem;
}
​
export const routes: Route[] = [
  {
    path: "/",
    component: lazy(() => import("../pages/test")),
  },
  {
    path: "/home",
    component: lazy(() => import("../pages/home")),
  },
  {
    path: "/about",
    component: lazy(() => import("../pages/about")),
    children: [
      {
        path: "mine",
        component: lazy(() => import("../pages/mine")),
      },
    ],
  },
];
​
export interface Route<T = any>
  extends Omit<RouteObject, "element" | "children"> {
  component: LazyExoticComponent<FC<T>>;
  children?: Route[];
}
​
export const withRoutes = (routes: Route[]): RouteObject[] => {
  const result: RouteObject[] = [];
  routes.forEach((item) => {
    const { component: Comp, children, ...reset } = item;
    const route = {
      ...reset,
      element: (
        <Suspense fallback={<Spin />}>
          <Comp />
        </Suspense>
      ),
      ...(Array.isArray(children) &&
        children.length > 0 && {
          children: withRoutes(children),
        }),
    };
    result.push(route);
  });
  return result;
};
​
// src/router/index.tsx
import { MenuProps } from "antd";
import { MailOutlined } from "@ant-design/icons";
import { useRoutes } from "react-router-dom";
​
import { routes, withRoutes } from "./routes";
import { getItem } from "./routes";
​
export const items: MenuProps["items"] = [
  getItem("菜单", "sub1", <MailOutlined />, [
    getItem("首页", "/home"),
    getItem("关于", "/about"),
  ]),
];
​
const Routes = () => useRoutes(withRoutes(routes));
​
export default Routes;

最后在App.tsx使用路由

import { useLocation, useNavigate } from "react-router-dom";
import { Menu } from "antd";
​
import { items } from "./router";
import Routes from "./router";
​
function App() {
  const location = useLocation();
  const navigator = useNavigate();
​
  const MenuClickHandle = (e: any) => {
    navigator(e.key);
  };
​
  return (
    <div className="App">
      <Menu
        items={items}
        selectedKeys={[`${location.pathname}`]}
        style={{ width: 256 }}
        // defaultSelectedKeys={[`${location.pathname}`]}
        defaultOpenKeys={["sub1"]}
        mode="inline"
        onClick={(e) => MenuClickHandle(e)}
      />
      <Routes></Routes>
    </div>
  );
}
​
export default App;

因为我在定义about路由的时候有给它子路由,所以我的about页面要加outlet标签,相当于vue里面的router-view标签

// src/pages/about.tsximport React, { memo } from "react";
import { Outlet } from "react-router-dom";
​
const about = memo(() => {
  return (
    <div>
      <h1>about</h1>
      <Outlet></Outlet>
    </div>
  );
});
​
export default about;
​

就此就完成了,先附上主要部分的完整代码

主要的路由与菜单部分完整代码

// src/router/index.tsx
import { MenuProps } from "antd";
import { MailOutlined } from "@ant-design/icons";
import { useRoutes } from "react-router-dom";
​
import { routes, withRoutes } from "./routes";
import { getItem } from "./routes";
​
export const items: MenuProps["items"] = [
  getItem("菜单", "sub1", <MailOutlined />, [
    getItem("首页", "/home"),
    getItem("关于", "/about"),
  ]),
];
​
const Routes = () => useRoutes(withRoutes(routes));
​
export default Routes;
// src/router/routes.tsx
import { MenuProps, Spin } from "antd";
import { RouteObject } from "react-router-dom";
import { FC, lazy, LazyExoticComponent, Suspense } from "react";
​
type MenuItem = Required<MenuProps>["items"][number];
​
export function getItem(
  label: React.ReactNode,
  key: React.Key,
  icon?: React.ReactNode,
  children?: MenuItem[],
  type?: "group"
): MenuItem {
  return {
    key,
    icon,
    children,
    label,
    type,
  } as MenuItem;
}
​
export const routes: Route[] = [
  {
    path: "/",
    component: lazy(() => import("../pages/test")),
  },
  {
    path: "/home",
    component: lazy(() => import("../pages/home")),
  },
  {
    path: "/about",
    component: lazy(() => import("../pages/about")),
    children: [
      {
        path: "mine",
        component: lazy(() => import("../pages/mine")),
      },
    ],
  },
];
​
export interface Route<T = any>
  extends Omit<RouteObject, "element" | "children"> {
  component: LazyExoticComponent<FC<T>>;
  children?: Route[];
}
​
export const withRoutes = (routes: Route[]): RouteObject[] => {
  const result: RouteObject[] = [];
  routes.forEach((item) => {
    const { component: Comp, children, ...reset } = item;
    const route = {
      ...reset,
      element: (
        <Suspense fallback={<Spin />}>
          <Comp />
        </Suspense>
      ),
      ...(Array.isArray(children) &&
        children.length > 0 && {
          children: withRoutes(children),
        }),
    };
    result.push(route);
  });
  return result;
};

最终效果展示图

image.png

image.png

image.png