react 项目路由配置(react-router-dom 版本 v6.3、v6.4)

根据 react-router-dom 的版本,有不同的方式

一、react-router-dom v6.3

用到的主要 api:

  • BrowserRouter
  • useRoutes
  • Outlet

下面是详细步骤:

1、index.js

  • BrowserRouter 用来实现 单页的客户端路由
  • 使用 BrowserRouter 包裹 App
  • 放在 顶级 位置,重要!!
  • 支持嵌套路由,用于 history 模式
  • hash 模式使用 HashRouter
js 复制代码
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <BrowserRouter>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </BrowserRouter>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

如果遇到下图这种报错,就是没有将 BrowserRouter 像上图一样放在 顶级,一定要放顶级!

2、routes.js

用 数组 描述路由,包含必要参数 pathelementchildren

例如:

js 复制代码
import { UserOutlined } from "@ant-design/icons";
import Abroad from "./pages/Abroad";
import Domestic from "./pages/Domestic";
import Layout from "./layout/index";
import { Navigate } from "react-router-dom";

const routes = [
  {
    title: "平台管理",
    path: "/manage",
    element: <Layout />,
    icon: <UserOutlined />,
    children: [
      {
        title: "境内平台管理",
        path: "/manage/domestic",
        element: <Domestic />,
        icon: <UserOutlined />,
      },
      {
        title: "境外平台管理",
        path: "/manage/abroad",
        element: <Abroad />,
        icon: <UserOutlined />,
      },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/manage/domestic" />,
  },
];

export default routes;

3、App.js

使用 useRoutes 渲染出一级路由,参数即为我们在上一步的路由数组

  • useRoutes 是 react-router-dom 库中提供的一个 Hook,用于 基于路由配置生成路由匹配器(Router Matcher)的方法
  • useRoutes 接收的路由配置对象应该是一个由 若干个路由配置组成的数组,每个路由配置包含以下属性:
    • path:字符串类型,表示 URL 路径匹配规则;
    • element:React 组件,表示如果 URL 匹配成功后要显示的组件;
    • children:嵌套子路由的路由配置数组。
js 复制代码
import React from "react";
import { useRoutes } from "react-router-dom";
import routes from "./routes";

const App = () => {
  const element = useRoutes(routes);
  return <>{element}</>;
};

export default App;

4、layout.jsx

实际场景,如后台管理项目,需要展示多级路由,我们一般会创建一个layout文件

  • 按照 左 Menu右 Content 的设定来举例
  • 嵌套的二级路由,使用 outlet 渲染(类似于vue中的 <router-view>
  • 例子中,包含了一些菜单处理的代码,如递归渲染、默认选中,可选择性观看
js 复制代码
import React, { useState } from "react";
import { MenuFoldOutlined, MenuUnfoldOutlined } from "@ant-design/icons";
import { Layout, Menu, Button, theme } from "antd";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import routes from "../routes/index";

const { Header, Sider, Content } = Layout;

// Menu格式处理
function getMenu(rout) {
  const rs = rout.map((item) => {
    return {
      label: item.title,
      key: item.path,
      icon: item.icon,
      children: item.children && getMenu(item.children),
    };
  });
  return rs;
}

// 递归层级
function findParents(key, tree) {
  let parents = [];
  function findParent(nodes, key) {
    for (let node of nodes) {
      if (node.path === key) {
        return true;
      }
      if (node.children && findParent(node.children, key)) {
        parents.push(node.path);
        return true;
      }
    }
    return false;
  }
  findParent(tree, key);
  parents.push(key);
  return parents;
}

// 获取当前路由所在层级
function getOpenKeys(pathname, list) {
  if (!pathname) return ["/manage", "/manage/domestic"];
  let keys = findParents(pathname, list);
  return keys;
}

const App = () => {
  const [collapsed, setCollapsed] = useState(false);
  const {
    token: { colorBgContainer, borderRadiusLG },
  } = theme.useToken();

  // 递归获取有效菜单项
  const list = routes.filter((item) => item.title);
  const items = getMenu(list);

  // 菜单,默认展开、选中处理
  const location = useLocation();
  const keys = getOpenKeys(location.pathname, list);
  const defaultSelectedKeys = keys;
  const defaultOpenKeys = keys;

  // 跳转
  let navigate = useNavigate();
  function handleClick(e) {
    navigate(e.key);
  }

  return (
    <Layout>
      <Sider trigger={null} collapsible collapsed={collapsed}>
        <div style={{ width: "100%", height: "80px" }}></div>
        {/* 菜单 */}
        <Menu
          mode="inline"
          theme="dark"
          defaultSelectedKeys={defaultSelectedKeys}
          defaultOpenKeys={defaultOpenKeys}
          onClick={handleClick}
          items={items}
        ></Menu>
      </Sider>
      <Layout>
        <Header
          style={{
            padding: 0,
            background: colorBgContainer,
          }}
        >
          <Button
            type="text"
            onClick={() => setCollapsed(!collapsed)}
            style={{ marginBottom: 16 }}
          >
            {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
          </Button>
        </Header>
        <Content
          style={{
            margin: "24px 16px",
            padding: 24,
            minHeight: 280,
            background: colorBgContainer,
            borderRadius: borderRadiusLG,
            overflowY: "auto",
          }}
        >
          {/* 二级路由 */}
          <Outlet />
          
        </Content>
      </Layout>
    </Layout>
  );
};
export default App;

v6.3 的版本,路由设置到此结束,接下来是 v6.4

二、react-router-dom v6.4

主要 api:

  • createBrowserRouter
  • RouterProvider
  • Outlet

在 v6.3 方案的基础上,换掉 index.js 和 App.js 即可

1、index.js

BrowserRouter 的使用去掉

js 复制代码
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

// v6.3 使用此API,v6.4使用会报错
// import { BrowserRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  // <BrowserRouter>
  <React.StrictMode>
    <App />
  </React.StrictMode>
  // </BrowserRouter>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

2、App.js

useRoutes 的使用去掉,增加 createBrowserRouterRouterProvider 的相关设置

  • createBrowserRouter 创建路由
  • 挂载到 RouterProviderrouter
cpp 复制代码
import React from "react";
import routes from "./routes";

// v6.3 userRoutes钩子
// import { useRoutes } from "react-router-dom";
// const App = () => {
//   const element = useRoutes(routes);
//   return <>{element}</>;
// };

// v6.4 createBrowserRouter + RouterProvider
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter(routes);
const App = () => {
  return (
    <>
      <RouterProvider router={router} />
    </>
  );
};

export default App;

然后就完成啦~

相关推荐
yuanyxh2 小时前
静默打印程序实现
前端·react.js·electron
前端老宋Running3 小时前
“受控组件”的诅咒:为什么你需要 React Hook Form + Zod 来拯救你的键盘?
前端·javascript·react.js
风止何安啊3 小时前
拿捏 React 组件通讯:从父子到跨组件的「传功秘籍」
前端·react.js·面试
韭菜炒大葱4 小时前
React 新手村通关指南:状态、组件与魔法 UI 🧙‍♂️
前端·javascript·react.js
用户120391129472611 小时前
从零掌握 React JSX:为什么它让前端开发像搭积木一样简单?
前端·react.js·面试
3秒一个大1 天前
JSX 基本语法与 React 组件化思想
前端·react.js
HexCIer1 天前
Arco Design 停摆!字节跳动 UI 库凉了?
react.js·前端框架
风止何安啊1 天前
React 入门秘籍:像搭积木一样写网页,JSX 让开发爽到飞起!
前端·react.js·前端框架
whyfail1 天前
React原理(暴力版)
前端·react.js
Crazy_Urus1 天前
深入解析 React 史上最严重的 RCE 漏洞 CVE-2025-55182
前端·安全·react.js