Router
在 React Router v7 中,官方把原先拆成两个包(react-router + react-router-dom)的代码合并回 react-router 这一个核心包。
因此,新项目只需安装 react-router,不必再装 react-router-dom;后者已标记为 deprecated,仅保留向后兼容 。
安装
bash
npm i react-router@latest
牛刀小试
ts
// 新建Home页面
import { NavLink } from "react-router"; // 路由跳转
export default function Home() {
return (
<div>
<h1>Home</h1>
<NavLink to="/about">About</NavLink>
</div>
);
}
// 新建About页面
export default function About() {
return (
<div>
<h1>About</h1>
</div>
);
}
// 配置router
import Home from "../pages/Home";
import About from "../pages/About";
import { createBrowserRouter } from "react-router";
const router = createBrowserRouter([
{
path: "/",
Component: Home,
},
{
path: "/about",
Component: About,
}
])
export default router;
// 引用router(App.tsx)
import { RouterProvider } from 'react-router'
import router from './router'
function App() {
return (
<>
<div className="App">
<RouterProvider router={router} />
</div>
</>
)
}
export default App
路由模式
| 模式 | URL 存在位置 | 典型场景 | 所在包(v7) |
|---|---|---|---|
| 1. BrowserRouter | 浏览器地址栏 | 线上 Web 站点 | react-router |
| 2. HashRouter | location.hash | 内网、单文件部署、老浏览器 | react-router |
| 3. MemoryRouter | 内存数组 | 测试、React Native、微前端 | react-router |
| 4. StaticRouter | 字符串路径 | 服务端渲染(SSR) | react-router/dom |
createBrowserRouter ------ "正常网址"
地址栏:https://example.com/about
刷新 404 → 需要服务器配回退 /* → index.html
ts
import { BrowserRouter } from 'react-router'
import Home from "../pages/Home";
import About from "../pages/About";
import { createBrowserRouter } from "react-router";
const router = createBrowserRouter([
{
path: "/",
Component: Home,
},
{
path: "/about",
Component: About,
}
])
export default router;
例如nginx

HashRouter ------ "# 后面自己玩"
地址栏:https://example.com/#/about
刷新不 404,无需服务端配置;SEO 几乎为零。
ts
import Home from "../pages/Home";
import About from "../pages/About";
import { createHashRouter } from "react-router";
const router = createHashRouter([
{
path: "/",
Component: Home,
},
{
path: "/about",
Component: About,
}
])
export default router;

MemoryRouter ------ "地址栏看不见"
适用于:单元测试(@testing-library/react)、React Native 导航嵌套、微前端子应用隐藏路由
ts
import Home from "../pages/Home";
import About from "../pages/About";
import { createHashRouter } from "react-router";
const router = createMemoryRouter ([
{
path: "/",
Component: Home,
},
{
path: "/about",
Component: About,
}
])
export default router;

StaticRouter ------ "服务端字符串"
客户端首屏直出,不维护历史栈;location 是只读字符串。
ts
// server.js (Node)
import { StaticRouter } from 'react-router/dom/server'
const html = ReactDOMServer.renderToString(
<StaticRouter location={req.path}> {/* 把 Node 收到的路径直接传进来 */}
<App />
</StaticRouter>
)
路由种类
嵌套路由
嵌套路由是指在父级路由下定义子路由,形成层级结构。适用于具有多层布局的应用程序,例如管理后台的侧边栏导航或带有
标签页的内容区域。
ts
import Home from "../pages/Home";
import About from "../pages/About";
import { createBrowserRouter } from "react-router";
import Layout from "../pages/Layout";
const router = createBrowserRouter([
{
path: "/index",
Component: Layout,
// 子路由
children: [
{
path: "about",
Component: About,
},
{
path: "home",
Component: Home,
},
]
},
])
export default router;
ts
import React from 'react';
import { Outlet } from 'react-router';
const Content: React.FC = () => (
// 父组件中需添加<Outlet />作为子路由的占位符。
<Outlet />
);
export default Content;
注:子路由的请求路径http://localhost:5173/index/home
最佳实践
- 保持嵌套层级不超过3层以避免复杂度。
- 使用命名路由简化长路径的跳转。
- 结合懒加载优化性能:
ts
// React Router懒加载
{ path: 'home', element: React.lazy(() => import('./Home.jsx')) }
布局路由
路由布局是指在Web应用中,通过定义不同的路由路径来组织和管理页面或视图的显示方式。前端框架如React、Vue、Angular等通常
提供路由功能,允许开发者根据URL的变化动态加载不同的组件或页面。
ts
const router = createBrowserRouter([
{
// path: '/index', //省略
Component: Layout,
children: [
{
path: 'home',
Component: Home,
},
{
path: 'about',
Component: About,
},
]
},
]);
索引路由
索引路由是一种通过建立索引来优化路由查找效率的技术,常用于网络通信、数据库查询或前端框架(如React Router)中。其核心
思想是将路由路径映射到快速可检索的数据结构(如哈希表、字典或树),减少线性搜索的时间复杂度。
索引路由 = 父路径尾部的默认子页,它没有 path,用 index: true 声明。下面把刚才的嵌套路由改成「索引路由」版本:访问
/index 时直接渲染 Home,不再额外拼路径。
ts
import { createBrowserRouter } from 'react-router-dom';
import Layout from './pages/Layout';
import Home from './pages/Home';
import About from './pages/About';
const router = createBrowserRouter([
{
path: '/index',
Component: Layout,
children: [
{ index: true, Component: Home }, // ← 索引路由
{ path: 'about', Component: About },
],
},
]);
export default router;
前缀路由
前缀路由(又叫通配路由)用来「把剩余路径全部收归当前路由处理」,写法就是在 path 末尾加 /*。
例如: 访问 /files/任意/任意/任意...... 都会落到 Files 组件,由它自己再决定到底展示什么。
ts
import { createBrowserRouter } from 'react-router-dom';
import Layout from './pages/Layout';
import Files from './pages/Files'; // 自己建的组件
const router = createBrowserRouter([
{
path: '/files',
Component: Layout,
children: [
{
path: '*', // ← 前缀路由(通配)
Component: Files,
},
],
},
]);
export default router;
Files.tsx 里可以继续用 useParams() 拿到「剩余段」:
ts
import { useParams } from 'react-router';
export default function Files() {
const params = useParams(); // params['*'] 就是剩余路径
return <h2>当前浏览路径:/files/{params['*']}</h2>;
}
访问验证
/files → Layout + Files(params[''] 为空)
/files/a/b/c → Layout + Files(params[''] = 'a/b/c')
动态路由
动态路由:路径里带「:参数名」占位符,匹配任意字符串,参数值通过 useParams() 读取。
ts
const router = createBrowserRouter([
{
path: '/',
Component: Layout,
children: [
{
path: 'home/:id',
Component: Home,
},
{
path: 'about',
Component: About,
},
]
},
]);
//在组件中获取参数
import { useParams } from "react-router";
function Card() {
let params = useParams();
console.log(params.id);
}
访问路径:http://localhost:3000/home/123
路由小DEMO
使用的组件库Ant Desgin
Content组件
ts
import React from 'react';
import { Outlet } from 'react-router';
const Content: React.FC = () => (
<Outlet />
);
export default Content;
Header组件
ts
import { Breadcrumb } from 'antd';
export function Headers() {
return (
<div>
<Breadcrumb
items={[
{
title: 'Home',
},
{
title: 'List',
},
{
title: 'APP',
},
{
title: 'An Application',
},
]}
/>
</div>
)
}
export default Headers
Menu组件
ts
import { AppstoreOutlined, MailOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { Menu as AntdMenu } from 'antd';
import { useNavigate } from 'react-router';
const Menu: React.FC = () => {
// Required 将变量设置为必填
type MenuItem = Required<MenuProps>['items'][number];
const items: MenuItem[] = [
{
key: '/home',
icon: <MailOutlined />,
label: 'Home',
},
{
key: '/about',
icon: <AppstoreOutlined />,
label: 'About',
}
];
const navigate = useNavigate();
const onClick: MenuProps['onClick'] = (e) => {
console.log('click', e);
navigate(e.key)
};
return < AntdMenu onClick={onClick} style={{ height: '100vh' }} mode="vertical" items={items} />
}
export default Menu;
Layout组件
ts
import React from 'react';
import { Layout as AntdLayout } from 'antd';
import Headers from './Header';
import Menu from './Menu';
import Content from './Content';
const Layout: React.FC = () => (
<AntdLayout >
<AntdLayout.Sider >
<Menu />
</AntdLayout.Sider>
<AntdLayout>
<Headers></Headers>
<Content></Content>
</AntdLayout>
</AntdLayout>
);
export default Layout;
目录结构
