React Router 6的学习

安装react-router-dom

npm i react-router-dom

支持不同的路由创建

createBrowserRouter

特点

  1. 推荐使用 的方式,基于 HTML5 的 History API。
  2. 支持用户友好的 URL,无需 #
  3. 适用于生产环境的绝大多数场景。

适用

使用现代浏览器,支持 pushState 和 replaceState 的情况

应用

javascript 复制代码
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Home from "../views/Home";
import About from "../views/About";
import ErrorPage from "../views/ErrorPage";

const router = createBrowserRouter([
  { path: "/", element: <Home /> },
  { path: "/about", element: <About /> },
  {
    path: "*", // 404 页面
    element: <ErrorPage />,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

tips

  1. 需要服务器支持,确保非根路径的页面请求被正确处理(常见问题是刷新后出现 404)
  2. 部署时,服务器通常需要配置以处理 SPA 应用

createHashRouter

特点

  1. URL 使用 #,如 http://example.com/#/about
  2. 不依赖服务器配置,适合快速开发和简单项目。
  3. 不推荐 ,因为URL 不够优雅,且 SEO 支持较差。

场景

  1. 静态站点部署(如 GitHub Pages)。
  2. 不支持 History API 的环境。

应用

javascript 复制代码
import { createHashRouter, RouterProvider } from "react-router-dom";
import Home from "../views/Home";
import About from "../views/About";

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

function App() {
  return <RouterProvider router={router} />;
}

export default App;

tips

  1. 无需服务器配置,但不适合对 URL 有美观或 SEO 要求的项目

createMemoryRouter

特点

  1. 不依赖浏览器环境,维护自己的内存中的路由栈。
  2. URL 不显示在浏览器地址栏
  3. 常用于非浏览器环境(如 React Native)或开发工具(如 Storybook)

场景

  1. 测试环境。
  2. 开发工具或需要自定义路由栈的应用

应用

javascript 复制代码
import { createMemoryRouter, RouterProvider } from "react-router-dom";
import Home from "../views/Home";
import About from "../views/About";

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

function App() {
  return <RouterProvider router={router} />;
}

export default App;

tips

  1. 开发中调试时有用,但生产环境通常不使用。
  2. URL 不可见,不适合需要 SEO 的场景。

createStaticRouter

特点

  1. 用于服务器端渲染(SSR)。
  2. 基于预定义的静态路由配置。
  3. 无需用户交互,生成的路由用于服务端直接渲染

场景

  1. SSR(服务器端渲染)应用,例如使用 React Router 与 Next.js 或 Remix

应用

javascript 复制代码
import { createStaticRouter, StaticRouterProvider } from "react-router-dom/server";
import Home from "../views/Home";
import About from "../views/About";

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

function App() {
  return <StaticRouterProvider router={router} />;
}

export default App;

tips

  1. createStaticRouter需要结合服务器环境。
  2. 主要用于预渲染生成的 HTML,例如静态页面生成器或 SSR 服务。

总结

|---------------------|---------------------------|------------------|------------------|
| 路由方式 | 特点 | 适用场景 | 优缺点 |
| createBrowserRouter | 基于 HTML5 History API,推荐使用 | 现代浏览器应用,生产环境 | URL 美观,需服务器支持 |
| createHashRouter | URL 包含 #,不依赖服务器 | 快速开发、简单项目,静态站点部署 | URL 不优雅,SEO 支持较差 |
| createMemoryRouter | 路由存储在内存中,无需浏览器环境 | 测试环境、开发工具,无浏览器场景 | 不适用于生产环境,URL 不可见 |
| createStaticRouter | 静态路由,用于 SSR 和静态页面生成 | 服务器端渲染 | 依赖服务端,无客户端交互 |

路由配置

  1. 使用 RoutesRoute 代替 React Router 5 的 Switch 和路由定义方式。
  2. 通过嵌套路由支持嵌套组件,可以实现更清晰的层次结构。
  3. path 属性定义路由路径,element 属性指定要渲染的组件
javascript 复制代码
// App.jsx

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/user/:id" element={<User />} />
      </Routes>
    </Router>
  );
}

function Home() {
  return <h1>Home Page</h1>;
}

function About() {
  return <h1>About Page</h1>;
}

function User({ id }) {
  return <h1>User Page for {id}</h1>;
}

动态路由

  1. 动态路由通过 :paramName 定义路径参数。
  2. 使用 useParams 钩子获取参数值。
  3. 动态路由使得可以根据 URL 参数渲染不同的内容,useParams 是获取路径参数的关键。
javascript 复制代码
import { useParams } from 'react-router-dom';

function User() {
  const { id } = useParams(); // 获取路径中的 id 参数
  return <h1>User ID: {id}</h1>;
}

导航

  1. 使用 useNavigate 替代旧版本中的 useHistory
  2. useNavigate 提供更灵活的导航方式。
  3. navigate 可以接受路径字符串,也可以接受对象形式,适合处理编程式导航
javascript 复制代码
import { useNavigate } from 'react-router-dom';

function Home() {
  const navigate = useNavigate();

  const goToAbout = () => {
    navigate('/about');
  };

  return (
    <div>
      <h1>Home Page</h1>
      <button onClick={goToAbout}>Go to About</button>
    </div>
  );
}

嵌套路由

  1. 支持组件内部嵌套路由。
  2. 子路由通过 Outlet 渲染。
  3. Outlet 是子路由的占位符,嵌套路由更适合复杂布局。
javascript 复制代码
import { Outlet, Link } from 'react-router-dom';

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <nav>
        <Link to="profile">Profile</Link>
        <Link to="settings">Settings</Link>
      </nav>
      <Outlet /> {/* 渲染子路由 */}
    </div>
  );
}

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="dashboard" element={<Dashboard />}>
          <Route path="profile" element={<Profile />} />
          <Route path="settings" element={<Settings />} />
        </Route>
      </Routes>
    </Router>
  );
}

重定向

  1. 使用 Navigate 组件进行页面重定向。
  2. 可在组件渲染时动态重定向。
  3. Navigate 是一个 JSX 组件,用于在路由中实现条件跳转
javascript 复制代码
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ isAuth, children }) {
  return isAuth ? children : <Navigate to="/login" />;
}

function App() {
  const isAuth = false; // 假设用户未登录

  return (
    <Router>
      <Routes>
        <Route
          path="/protected"
          element={
            <ProtectedRoute isAuth={isAuth}>
              <ProtectedPage />
            </ProtectedRoute>
          }
        />
        <Route path="/login" element={<Login />} />
      </Routes>
    </Router>
  );
}

数据加载

  1. React Router 6.4+ 引入了 loaderuseLoaderData,用于预加载路由数据。
  2. 支持异步加载,优化页面渲染体验。
  3. loader 提供异步数据加载,提升数据获取的灵活性,useLoaderData 获取加载的数据。
javascript 复制代码
import { createBrowserRouter, RouterProvider, useLoaderData } from 'react-router-dom';

function UserProfile() {
  const data = useLoaderData(); // 获取预加载的数据
  return <h1>User Name: {data.name}</h1>;
}

const router = createBrowserRouter([
  {
    path: "/user/:id",
    element: <UserProfile />,
    loader: async ({ params }) => {
      const response = await fetch(`/api/user/${params.id}`);
      return response.json();
    },
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

路由懒加载

  1. 减少首屏加载时间,提高性能;按需加载组件,降低内存占用;提升用户体验,特别是对于大型应用。
  2. 首次加载某个路由可能会有短暂延迟;如果 fallback 设计不当,可能导致用户体验下降;对 SEO 不友好,需配合服务器端渲染(SSR)解决。
  3. React.lazy(() => import('./ComponentPath')) 实现组件按需加载。
  4. Suspense用于显示加载状态(如 Loading...)直到懒加载组件加载完成
javascript 复制代码
import React from "react";

const Home = React.lazy(() => import("../views/Home"));
const About = React.lazy(() => import("../views/About"));
const Dashboard = React.lazy(() => import("../views/Dashboard"));

const routes = [
  {
    path: "/",
    element: (
      <React.Suspense fallback={<div>Loading...</div>}>
        <Home />
      </React.Suspense>
    ),
  },
  {
    path: "/about",
    element: (
      <React.Suspense fallback={<div>Loading...</div>}>
        <About />
      </React.Suspense>
    ),
  },
  {
    path: "/dashboard",
    element: (
      <React.Suspense fallback={<div>Loading...</div>}>
        <Dashboard />
      </React.Suspense>
    ),
  },
];

export default routes;
javascript 复制代码
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import routes from "./routes";

const router = createBrowserRouter(routes);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

路由保护

  1. 使用高阶组件模式或条件渲染实现路由保护。
  2. 常与 Navigate 和认证逻辑结合。
javascript 复制代码
function ProtectedRoute({ isAuth, children }) {
  return isAuth ? children : <Navigate to="/login" />;
}

错误处理

  1. 支持 errorElement 处理路由级别的错误。
javascript 复制代码
const router = createBrowserRouter([
  {
    path: "/",
    element: <Home />,
    errorElement: <ErrorPage />, // 错误处理组件
  },
]);

function ErrorPage() {
  return <h1>Something went wrong!</h1>;
}

综合案例

javascript 复制代码
src/
├── router/
│   └── index.jsx  // 路由配置
├── views/
│   ├── Home.jsx   // 首页
│   ├── Login.jsx  // 登录页
│   ├── Content.jsx  // 内容页 (嵌套路由)
│   ├── ErrorPage.jsx // 错误页面
│   └── Protected.jsx // 受保护的页面
├── App.jsx        // 应用入口
└── main.jsx       // 渲染入口
javascript 复制代码
// src/router/index.jsx
import { createBrowserRouter } from "react-router-dom";
import Home from "../views/Home";
import Login from "../views/Login";
import ErrorPage from "../views/ErrorPage";
import Content from "../views/Content";
import Protected from "../views/Protected";
import { Navigate } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Navigate to="/home" replace />, // 重定向到 /home
  },
  {
    path: "/home",
    element: <Home />,
    errorElement: <ErrorPage />,
    children: [
      {
        path: "content",
        element: <Content />,
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
    errorElement: <ErrorPage />,
  },
  {
    path: "/protected",
    element: <ProtectedRoute>
      <Protected />
    </ProtectedRoute>,
    errorElement: <ErrorPage />,
  },
  {
    path: "*", // 404 页面
    element: <ErrorPage />,
  },
]);

// 模拟受保护的路由
function ProtectedRoute({ children }) {
  const isAuthenticated = false; // 假设用户未登录
  return isAuthenticated ? children : <Navigate to="/login" replace />;
}

export default router;

页面组件:src/views

javascript 复制代码
// Home.jsx
import { Outlet, Link } from "react-router-dom";

function Home() {
  return (
    <div>
      <h1>Home Page</h1>
      <nav>
        <Link to="/home/content">Go to Content</Link>
        <Link to="/protected">Go to Protected Page</Link>
      </nav>
      <Outlet /> {/* 嵌套路由 */}
    </div>
  );
}

export default Home;
javascript 复制代码
//Login.jsx
import { useNavigate } from "react-router-dom";

function Login() {
  const navigate = useNavigate();

  const handleLogin = () => {
    // 模拟登录操作
    alert("Logged in!");
    navigate("/home"); // 登录后跳转到首页
  };

  return (
    <div>
      <h1>Login Page</h1>
      <button onClick={handleLogin}>Login</button>
    </div>
  );
}

export default Login;
javascript 复制代码
//Content.jsx
function Content() {
  return <h1>Content Page</h1>;
}

export default Content;
javascript 复制代码
//Protected.jsx
function Protected() {
  return <h1>Protected Page: You are authenticated!</h1>;
}

export default Protected;
javascript 复制代码
//ErrorPage.jsx
function ErrorPage() {
  return <h1>404 Not Found</h1>;
}

export default ErrorPage;
javascript 复制代码
// src/App.js
import { RouterProvider } from "react-router-dom";
import router from "./router";

function App() {
  return (
    <div>
      <RouterProvider router={router} />
    </div>
  );
}

export default App;
javascript 复制代码
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

效果

相关推荐
m0_7482352444 分钟前
前端:HTML、CSS、JS、Vue
前端·javascript·html
半夏知半秋1 小时前
unity打包流程整理-Windows/Mac/Linux平台
windows·笔记·学习·macos·unity·游戏引擎
君逸~~1 小时前
RK3568(二)——字符设备驱动开发
linux·驱动开发·笔记·学习·rk3568
Octopus20771 小时前
【C++】AVL树
开发语言·c++·笔记·学习
Charonmomo1 小时前
React - echarts 世界地图,中国地图绘制
javascript·react.js·echarts
灵性(๑>ڡ<)☆1 小时前
智慧商城项目2(vue核心技术与实战)
前端·javascript·vue.js
奶香臭豆腐2 小时前
C++ 泛编程 —— 函数模板(中)
开发语言·c++·学习
没资格抱怨2 小时前
分配角色业务
javascript·vue.js·elementui
小政爱学习!2 小时前
点击按钮打开dialog嵌套表格checked数据关闭dialog回显checked数据
javascript·vue.js·elementui
一周七喜h2 小时前
vue2 el-table实现跨页多选功能
javascript·vue.js·elementui