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;

然后就完成啦~

相关推荐
Revolution612 小时前
React 组件重新渲染时,到底重新执行了什么
前端·react.js·面试
林焱_RPAAI2 小时前
影刀RPA技术深度:CSS选择器高级实战指南——伪类属性选择器与性能对比完全解析
vue.js·react.js
名字还没想好☜9 小时前
React 受控输入框光标跳到末尾:格式化输入时的 selection 丢失 bug 与修复
前端·javascript·react.js·bug·react·next.js
10share9 小时前
React 新一代样式隔离方案 —— 编译时、零运行时、原生写法
前端·react.js
光影少年10 小时前
RN 的EventEmitter 双向通信
前端·react native·react.js
GuWenyue1 天前
90%前端写React+TS都踩坑!从组件类型、单向数据流到本地存储完整实战
前端·react.js
张元清1 天前
React useThrottle Hook:节流值与回调(2026)
javascript·react.js
烬羽1 天前
React 状态提升:一个 ColorPicker,彻底搞懂状态该放哪里
react.js·typescript·设计
console.log('npc')1 天前
React 跨项目集成实战:iframe 实现子项目详情弹窗
前端·javascript·react.js
无人生还1 天前
从 Vue3 到 React · 快速上手系列第 8 篇:组件通信与 Context(对标插槽与 provide/inject)
前端·vue.js·react.js