安装react-router-dom
npm i react-router-dom
支持不同的路由创建
createBrowserRouter
特点
- 推荐使用的方式,基于 HTML5 的 History API。
- 支持用户友好的 URL,无需
#
。 - 适用于生产环境的绝大多数场景。
适用
使用现代浏览器,支持 pushState 和 replaceState 的情况
应用
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
- 需要服务器支持,确保非根路径的页面请求被正确处理(常见问题是刷新后出现 404)
- 部署时,服务器通常需要配置以处理 SPA 应用
createHashRouter
特点
- URL 使用
#
,如http://example.com/#/about
。 - 不依赖服务器配置,适合快速开发和简单项目。
- 不推荐,因为 URL 不够优雅,且 SEO 支持较差。
场景
- 静态站点部署(如 GitHub Pages)。
- 不支持 History API 的环境。
应用
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
- 无需服务器配置,但不适合对 URL 有美观或 SEO 要求的项目
createMemoryRouter
特点
- 不依赖浏览器环境,维护自己的内存中的路由栈。
- URL 不显示在浏览器地址栏。
- 常用于非浏览器环境(如 React Native)或开发工具(如 Storybook)
场景
- 测试环境。
- 开发工具或需要自定义路由栈的应用
应用
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
- 开发中调试时有用,但生产环境通常不使用。
- URL 不可见,不适合需要 SEO 的场景。
createStaticRouter
特点
- 用于服务器端渲染(SSR)。
- 基于预定义的静态路由配置。
- 无需用户交互,生成的路由用于服务端直接渲染
场景
- SSR(服务器端渲染)应用,例如使用 React Router 与 Next.js 或 Remix
应用
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
- createStaticRouter需要结合服务器环境。
- 主要用于预渲染生成的 HTML,例如静态页面生成器或 SSR 服务。
总结
路由方式 | 特点 | 适用场景 | 优缺点 |
createBrowserRouter | 基于 HTML5 History API,推荐使用 | 现代浏览器应用,生产环境 | URL 美观,需服务器支持 |
createHashRouter | URL 包含 # ,不依赖服务器 | 快速开发、简单项目,静态站点部署 | URL 不优雅,SEO 支持较差 |
createMemoryRouter | 路由存储在内存中,无需浏览器环境 | 测试环境、开发工具,无浏览器场景 | 不适用于生产环境,URL 不可见 |
createStaticRouter | 静态路由,用于 SSR 和静态页面生成 | 服务器端渲染 | 依赖服务端,无客户端交互 |
路由配置
- 使用
Routes
和Route
代替 React Router 5 的Switch
和路由定义方式。 - 通过嵌套路由支持嵌套组件,可以实现更清晰的层次结构。
path
属性定义路由路径,element
属性指定要渲染的组件。
// 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>;
}
动态路由
- 动态路由通过
:paramName
定义路径参数。 - 使用
useParams
钩子获取参数值。 - 动态路由使得可以根据 URL 参数渲染不同的内容,
useParams
是获取路径参数的关键。
import { useParams } from 'react-router-dom';
function User() {
const { id } = useParams(); // 获取路径中的 id 参数
return <h1>User ID: {id}</h1>;
}
导航
- 使用
useNavigate
替代旧版本中的useHistory
。 useNavigate
提供更灵活的导航方式。navigate
可以接受路径字符串,也可以接受对象形式,适合处理编程式导航。
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>
);
}
嵌套路由
- 支持组件内部嵌套路由。
- 子路由通过
Outlet
渲染。 Outlet
是子路由的占位符,嵌套路由更适合复杂布局。
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>
);
}
重定向
- 使用
Navigate
组件进行页面重定向。 - 可在组件渲染时动态重定向。
Navigate
是一个 JSX 组件,用于在路由中实现条件跳转
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>
);
}
数据加载
- React Router 6.4+ 引入了
loader
和useLoaderData
,用于预加载路由数据。 - 支持异步加载,优化页面渲染体验。
loader
提供异步数据加载,提升数据获取的灵活性,useLoaderData
获取加载的数据。
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} />;
}
路由懒加载
- 减少首屏加载时间,提高性能;按需加载组件,降低内存占用;提升用户体验,特别是对于大型应用。
- 首次加载某个路由可能会有短暂延迟;如果
fallback
设计不当,可能导致用户体验下降;对 SEO 不友好,需配合服务器端渲染(SSR)解决。 React.lazy(() => import('./ComponentPath'))
实现组件按需加载。Suspense
用于显示加载状态(如Loading...
)直到懒加载组件加载完成
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;
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import routes from "./routes";
const router = createBrowserRouter(routes);
function App() {
return <RouterProvider router={router} />;
}
export default App;
路由保护
- 使用高阶组件模式或条件渲染实现路由保护。
- 常与
Navigate
和认证逻辑结合。
function ProtectedRoute({ isAuth, children }) {
return isAuth ? children : <Navigate to="/login" />;
}
错误处理
- 支持
errorElement
处理路由级别的错误。
const router = createBrowserRouter([
{
path: "/",
element: <Home />,
errorElement: <ErrorPage />, // 错误处理组件
},
]);
function ErrorPage() {
return <h1>Something went wrong!</h1>;
}
综合案例
src/
├── router/
│ └── index.jsx // 路由配置
├── views/
│ ├── Home.jsx // 首页
│ ├── Login.jsx // 登录页
│ ├── Content.jsx // 内容页 (嵌套路由)
│ ├── ErrorPage.jsx // 错误页面
│ └── Protected.jsx // 受保护的页面
├── App.jsx // 应用入口
└── main.jsx // 渲染入口
// 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
// 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;
//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;
//Content.jsx
function Content() {
return <h1>Content Page</h1>;
}
export default Content;
//Protected.jsx
function Protected() {
return <h1>Protected Page: You are authenticated!</h1>;
}
export default Protected;
//ErrorPage.jsx
function ErrorPage() {
return <h1>404 Not Found</h1>;
}
export default ErrorPage;
// src/App.js
import { RouterProvider } from "react-router-dom";
import router from "./router";
function App() {
return (
<div>
<RouterProvider router={router} />
</div>
);
}
export default App;
// 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")
);