5.ReactRouter路由与Redux状态管理

书诚小驿2025/07/01前端知识库React

一、ReactRouter 路由

1、ReactRouter 基础路由介绍

  1. 安装 ReactRouter
npm i react-router-dom
  1. /src/router/index.ts 中创建路由配置
//createBrowserRouter: history模式 createBrowserRouter: hash模式
import { createBrowserRouter } from "react-router-dom";
import type { RouteObject } from "react-router-dom";
import Home from "../views/Home";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Home />,
  },
]);

export default router;
  1. /src/index.tsx中配置路由

路由生效组件<RouterProvider router={router} />

import { RouterProvider } from "react-router-dom";
import router from "./router";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);
  1. /src/views/Home/Home.tsx
import React from "react";

const Home = () => {
  return <div>Home</div>;
};

export default Home;

2、React Router v6 的嵌套路由

  1. src/views/Layout/Layout.tsx中创建布局组件,引入Outlet组件
import React from "react";
// Outlet组件用于显示子路由
import { Outlet } from "react-router-dom";
import Home from "../Home";
import User from "../User";

const Layout = () => {
  return (
    <div>
      <div className="slider">菜单</div>
      <div className="content">
        <Outlet />
      </div>
    </div>
  );
};

export default Layout;
  1. 新建src/views/User/User.tsx
import React from "react";

const User = () => {
  return <div>User</div>;
};

export default User;
  1. src/router/index.ts中配置子路由
import { createBrowserRouter } from "react-router-dom";
import type { RouteObject } from "react-router-dom";
import Home from "../views/Home";
import User from "../views/User";
import Layout from "../views/Layout";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout />,
    children: [
      {
        path: "",
        element: <Home />,
      },
      {
        path: "user",
        element: <User />,
      },
    ],
  },
]);

export default router;

3、路由表组件写法

  1. src/router/index.ts
import {
  Route,
  createRoutesFromElements,
  createBrowserRouter,
} from "react-router-dom";
import Home from "../views/Home/Home";
import About from "../views/About/About";
import App from "../App";
const routes = createRoutesFromElements(
  <Route path="/" element={<App />}>
    <Route path="" element={<Home />}></Route>
    <Route path="about" element={<About />}></Route>
  </Route>
);
const router = createBrowserRouter(routes);

export default router;
  1. src/views/Layout/Layout.tsx
import React from "react";
import { Link, Outlet } from "react-router-dom";
import Home from "../Home";
import User from "../User";

const Layout = () => {
  return (
    <div>
      <div className="slider">菜单</div>
      <div className="content">
        <Outlet />
        <Link to="/">Home</Link>
        <Link to="/user">User</Link>
      </div>
    </div>
  );
};

export default Layout;

二、动态路由模式模式与编程式路由模式

1、动态路由:path:/user/:iduseParams函数

  1. src/router/index.js
import { createBrowserRouter } from "react-router-dom";
import App from "../App.jsx";
import User from "../views/User/User";
import UserInfo from "../views/UserInfo/UserInfo";

// 路由表
const routes = [
  {
    path: "/",
    element: <App />,
    children: [
      {
        path: "user",
        element: <User />,
        children: [
          {
            path: "userinfo/:id", // 动态路由
            element: <UserInfo />,
          },
        ],
      },
    ],
  },
];

const router = createBrowserRouter(routes);

export default router;
  1. src/views/User/User.jsx
import "./User.scss";
import { Outlet, Link } from "react-router-dom";
export default function User() {
  return (
    <>
      <div></div>
      <Link to="/user/userinfo/123">userInfo123</Link> ||
      <Link to="/user/userinfo/456">userInfo456</Link>
      <Outlet />
    </>
  );
}
  1. src/views/UserInfo/UserInfo.jsx
import "./UserInfo.scss";
import { useParams } from "react-router-dom";
export default function UserInfo() {
  // 获取动态路由参数
  const params = useParams();
  return <div>UserInfo,{params.id}</div>;
}

NavLink 组件默认会添加active类名,样式需要自己添加

  1. src/views/User/User.jsx
import "./User.scss";
import { Outlet, NavLink } from "react-router-dom";
export default function User() {
  return (
    <>
      <div></div>
      <NavLink to="/user/userinfo/123">userInfo123</NavLink> ||
      <NavLink to="/user/userinfo/456">userInfo456</NavLink>
      <Outlet />
    </>
  );
}
  1. src/views/User/User.scss
.active {
  color: aqua;
}

如果需要默认设置选择和未选中样式,可以在NavLink组件上设置activeClassNameactiveStyle属性

  1. src/views/User/User.jsx
import React from "react";
import "./User.scss";
import { Outlet, NavLink } from "react-router-dom";
export default function User() {
  return (
    <>
      <div></div>
      <NavLink
        className={({ isActive }) => (isActive ? "curSelect1" : "none")}
        to="/user/userinfo/123"
      >
        userInfo123
      </NavLink>
      ||
      <NavLink
        className={({ isActive }) => (isActive ? "curSelect2" : "none")}
        to="/user/userinfo/456"
      >
        userInfo456
      </NavLink>
      <Outlet />
    </>
  );
}
  1. src/views/User/User.scss
.curSelect1 {
  color: aqua;
}
.curSelect2 {
  color: pink;
}

3、编程式路由跳转useNavigate

useNavigate 可以在组件内进行路由跳转

  1. src/views/User/User.jsx
import React from "react";
import "./User.scss";
import { Outlet, useNavigate } from "react-router-dom";
export default function User() {
  const navigate = useNavigate();
  const handleClick = () => {
    navigate("/user/userinfo/123");
  };
  return (
    <>
      <div></div>
      <button onClick={handleClick}>click to userinfo</button>
      <Outlet />
    </>
  );
}

三、useLocationuseSearchParams

1、useLocation 可以获取当前路由信息

其中有location.hash表示当前路由的哈希值,location.pathname表示当前路由的路径名,location.search表示当前路由的查询参数,location.state表示当前路由的额外信息,location.key表示当前路由的 key

src/views/User/User.jsx

import React from "react";
import "./User.scss";
import { Outlet, useNavigate } from "react-router-dom";
export default function User() {
  const navigate = useNavigate();
  const handleClick = () => {
    navigate("/user/userinfo/12?34#56", { state: { foo: 789 } });
  };
  return (
    <>
      <div></div>
      <button onClick={handleClick}>click to userinfo</button>
      <Outlet />
    </>
  );
}

src/views/UserInfo/UserInfo.jsx中使用 useLocation

import "./UserInfo.scss";
import { useLocation } from "react-router-dom";
export default function UserInfo() {
  const location = useLocation();
  console.log(location, "useLocation");
  return <div>UserInfo</div>;
}

显示的结果是

{
  hash: "#56",
  pathname: "/user/userinfo/123",
  search: "?34",
  state: { foo: 789 },
  key: "63o4wd7k"
}

2、useSearchParams 可以获取当前路由的查询参数,如获取?username=xiaomu中的xiaomu

src/views/User/User.jsx

import React from "react";
import "./User.scss";
import { Outlet, useNavigate } from "react-router-dom";
export default function User() {
  const navigate = useNavigate();
  const handleClick = () => {
    navigate("/user/userinfo/123?username=xiaobu");
  };
  return (
    <>
      <div></div>
      <button onClick={handleClick}>click to userinfo</button>
      <Outlet />
    </>
  );
}

src/views/UserInfo/UserInfo.jsx中使用useSearchParams,通过searchParams.get('username')获取和通过setSearchParams({age:18})更改当前路由的查询参数

import "./UserInfo.scss";
import { useSearchParams } from "react-router-dom";
export default function UserInfo() {
  const [searchParams, setSearchParams] = useSearchParams();
  console.log(searchParams.get("username"));
  const handleClick = () => {
    setSearchParams({ age: 18 });
  };
  return (
    <>
      <div>UserInfo</div>
      <button onClick={handleClick}>修改username</button>
    </>
  );
}

四、默认路由展示与重定向路由与 404 处理

1、默认路由展示

默认路由:{index:true,element:

默认路由展示
}

src/views/About/About.jsx通过Outlet展示路由

import React from "react";
import "./About.scss";
import { Outlet } from "react-router-dom";

export default function About() {
  return (
    <>
      <div>About</div>
      <Outlet />
    </>
  );
}
import { createBrowserRouter } from "react-router-dom";
import App from "../App.jsx";
import Home from "../views/Home/Home";
import About from "../views/About/About";

const routes = [
  {
    path: "/",
    element: <App />,
    children: [
      {
        path: "/home",
        element: <Home />,
      },
      {
        path: "/about",
        element: <About />,
        // 默认路由展示
        children: [
          {
            index: true,
            element: <div>默认页面展示</div>,
          },
        ],
      },
    ],
  },
];

const router = createBrowserRouter(routes);

export default router;

2、重定向路由

重定向路由:{index:true,element:}

3、404 处理

errorElement:

404

const routes = [
  {
    path: "/",
    element: <App />,
    errorElement: <div>404</div>,
  },
];

若是只在某一个页面下进行 404 处理,可以这样写

const routes = [
  {
    path: "/",
    element: <App />,
    children: [
      {
        path: "/home",
        element: <Home />,
      },
      {
        path: "/about",
        element: <About />,
        children: [
          {
            path:'*'
            element: <div>404</div>,
          },
        ],
      },
    ],
  },
];

五、loader 函数与 redirect 方法

1、loader 函数

  1. loader 函数进行路由前触发,配合 redirect 做权限拦截
  2. useLoaderData()获取 loader 函数返回的数据

src/router/index.js中使用 loader 函数

const routes = [
  {
    path: "/",
    element: <App />,
    errorElement: <div>404</div>,
    children: [
      {
        path: "/home",
        element: <Home />,
        // loader 函数进行路由前触发
        loader: async () => {
          console.log("loader");
          // 经过一秒后返回数据
          let res = await new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve({ errorcode: 0 });
            }, 1000);
          });
          return res;
        },
      },
    ],
  },
];

useLoaderData中获取 loader 函数返回的数据

import React from "react";
import "./Home.scss";
import { useLoaderData } from "react-router-dom";

export default function Home() {
  const data = useLoaderData();
  console.log(data); // {errorcode:0}
  return <div>Home</div>;
}

2、redirect 方法

redirect 方法进行路由后触发,配合 loader 做权限拦截

  1. 创建一个BeforeEach包裹根组件

  2. 自定义元信息 meta

  3. 组件中获取 meta 信息:matchRoutesuseLocation

src/components/BeforeEach/BeforeEach.jsx

import React from "react";
import { useLocation, matchRoutes, Navigate } from "react-router-dom";
import { routes } from "../../router";
export default function BeforeEach(props) {
  const location = useLocation();
  const matchs = matchRoutes(routes, location);
  // 获取当前路由的元信息
  const { auth } = matchs[matchs.length - 1].route.meta;
  if (auth) {
    return <Navigate to="/login" />;
  } else {
    return <div>{props.children}</div>;
  }
}

src/router/index.js中使用 BeforeEach 组件

import { createBrowserRouter } from "react-router-dom";
import App from "../App.jsx";
import Home from "../views/Home/Home";
import Login from "../views/Login/Login";
import About from "../views/About/About";
import BeforeEach from "../components/BeforeEach/BeforeEach";

// 路由表
export const routes = [
  {
    path: "/",
    element: (
      <BeforeEach>
        <App />
      </BeforeEach>
    ),
    errorElement: <div>404</div>,
    children: [
      {
        path: "/",
        element: <Home />,
        meta: { title: "首页", auth: false },
      },
      {
        path: "/login",
        element: <Login />,
        meta: { title: "登录", auth: false },
      },
      {
        path: "/about",
        element: <About />,
        meta: { title: "关于", auth: true },
      },
    ],
  },
];

const router = createBrowserRouter(routes);

export default router;
最后更新时间' 2025/7/1 23:18:45