React Router v7 入门指南
本教程基于 react router v7 版本,旨在快速实现一个 react router 的案例功能。
详细内容请查看 react router官网
快速启动一个 react 项目
使用 vite 快速创建一个 react 项目
1
| pnpm create vite my-vue-app --template react
|
安装依赖
启动项目
实现基础路由功能
安装 react router 库
新建路由页面
在 src 里新建 pages 目录,里面新建 about.jsx,home.jsx,list.jsx, 各 react 元素可以随意返回一些内容,以供路由匹配展示。
内容类似下面这样:
1 2 3 4 5 6 7 8
| export default function About() { return ( <div> About Page </div> ) }
|
配置路由
修改 main.jsx 文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { createRoot } from 'react-dom/client' import { BrowserRouter, Routes, Route } from 'react-router' import './index.css' import App from './App.jsx' import Home from './pages/home.jsx' import List from './pages/list.jsx' import About from './pages/about.jsx'
createRoot(document.getElementById('root')).render( <BrowserRouter> <Routes> <Route path='/' element={<App />}> <Route index element={<Home />}></Route> <Route path='list' element={<List />}></Route> <Route path='about' element={<About />}></Route> </Route> </Routes> </BrowserRouter>, )
|
react router 有2种路由模式, BrowserRouter 和 HashRouter。
- BrowserRouter: 使用现代浏览器的 History API(pushState 和 replaceState)来同步 URL 和应用程序状态。
- HashRouter:使用 URL 中的哈希片段(#)来保存路由状态。
使用 Routes 包括 Route 组件,可以创建我们的路由。Route 组件的 path 属性代表路由绑定的路径,element 代表路由要展示的元素内容。
有一个 Route 没有 path 属性,但是它出现 index 属性,代表它是父路由的默认子路由,也就是说当我们访问“根路径” 就能看到 Home 元素。
完成路由跳转和页面展示
修改 main,jsx 文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { Link } from 'react-router' import { Outlet } from 'react-router' import './App.css'
function App() {
return ( <div> <h1>react router demo v6</h1> <nav> <Link to="/" style={{ marginRight: '15px' }}>首页</Link> <Link to="/list" style={{ marginRight: '15px' }}>列表</Link> <Link to="/about" style={{ marginRight: '15px' }}>关于</Link> </nav>
<Outlet /> </div> ) }
export default App
|
使用 Link 组件的 to 属性可以配置路由的跳转地址,Outlet 组件用于展示当前路由匹配的页面(组件)。
重新启动项目,现在你可以看到如下图展示的内容,点击 home、about、list,可以看到路由的底部展示的渲染的内容发生了变化,并浏览器地址也对应更新。

至此,我们已经完成了基础的路由配置和、跳转以及页面的展示。
匹配 404 页面
通常当我们访问一个不存在的页面的地址的时候,需要展示一个 404 页面。通常这个页面不属于根页面的子路由。
在 src/pages 目录里面新建一个 404.jsx 文件,内容如下:
1 2 3 4 5
| export default function NotFound() { return ( <div>Not Found 404</div> ) }
|
修改 main.jsx 路由配置,就能完成我们需要的功能了,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import {createRoot} from 'react-dom/client' import {BrowserRouter, Routes, Route} from 'react-router' import './index.css' import App from './App.jsx' import Home from './pages/home.jsx' import List from './pages/list.jsx' import About from './pages/about.jsx' import NotFound from "./pages/404.jsx";
createRoot(document.getElementById('root')).render( <BrowserRouter> <Routes> <Route path='/' element={<App/>}> <Route index element={<Home/>}></Route> <Route path='list' element={<List/>}></Route> <Route path='about' element={<About/>}></Route> </Route> {/* 匹配 404 页面 */} <Route path='*' element={<NotFound/>}></Route> </Routes> </BrowserRouter>, )
|
现在在浏览器访问 http://localhost:5173/1 , 页面就会展示 “Not Found 404” 了。
获取路由参数 params 和 query
获取路由 params
配置 list 路由的子路由 list/id
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| createRoot(document.getElementById('root')).render( <BrowserRouter> <Routes> <Route path='/' element={<App/>}> <Route index element={<Home/>}></Route> <Route path='list' element={<List/>}> {/*新增子路由,list/id*/} <Route path=':id' element={<ListDetail/>}></Route> </Route> <Route path='about' element={<About/>}></Route> </Route> <Route path='*' element={<NotFound/>}></Route> </Routes> </BrowserRouter>, )
|
在 src/pages 目录新建 list-detail.jsx 文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import {useParams} from "react-router";
export default function ListDetail() {
const params = useParams() console.log(params)
return ( <div> List Detail Page id: {params.id} </div> ) }
|
修改 list.jsx 文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import {Link, Outlet} from "react-router";
export default function List() { const data = [ { id: 1, name: '订单1' }, { id: 2, name: '订单2' } ];
return ( <div> { data.map( (item) => <Link style={{marginRight: '15px'}} to={ `/list/${item.id}`} key={item.id} > detail {item.name} </Link> ) }
{/* 展示子页面的内容 */} <Outlet></Outlet> </div> ) }
|
现在重新启动项目,你会看到下面这样的界面:

点击 列表 下面的 detail 订单 1 , 可以看到展示了 List Detail Page id: 1。
使用 useParams() 方法可以获取到 params 对象,里面包含了相关的参数信息。
获取路由 query
修改 list.jsx 文件,新增一个携带 query 参数的 Link 组件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| return ( <div> { data.map( (item) => <Link style={{marginRight: '15px'}} to={ `/list/${item.id}`} key={item.id} > detail {item.name} </Link> ) }
{/* 新增一个携带 query 参数的 Link 组件 */} <Link to='/list/3?type=a' >detail type=a</Link>
{/* 展示子页面的内容 */} <Outlet></Outlet> </div> )
|
修改 list-detail.jsx 文件,加入获取路由 query 参数的代码,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import {useParams, useSearchParams} from "react-router";
export default function ListDetail() { const params = useParams() console.log(params)
let [searchParams] = useSearchParams(); console.log(searchParams) console.log(searchParams.get('type'))
return ( <div> List Detail Page id: {params.id} </div> ) }
|
点击 新增的 Link 组件,跳转到 list-detail 页面,展示内容为 “List Detail Page id: 3”。

查看控制台可以发现我们获取去到了路由的 query 参数 type=a; 这里说明一下 useSearchParams() 方法返回的数组中,第一个元素是 一个 URLSearchParams 实例; URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串。URLSearchParams 接口 MDN
如果需要获取更多路由信息,可以使用 useLocation 方法:
1 2
| let location = useLocation(); console.log(location)
|

编程式导航
有些时候我们需要使用 js 主动去触发页面的跳转,可以使用方法 useNavigate。
params 和 query 参数你可以直接写在跳转链接里面, 例如 ‘/list/1?type=a’,不在演示。
1 2 3 4 5
| const navigate = useNavigate(); const backToHome = () => { navigate('/') }
|
重定向
自定义导航守卫
在项目开发的过程中,一般我们会有这样的需求:有些页面可以随意访问,但是部分页面必须用户登录之后才能访问。我们可以给路由配置一个白名单,如果当前访问页面的路径在白名单里面,就能正常访问。反之,如果访问的页面需要权限,用户必须登录之后才能正常访问。不能访问的页面当用户触发跳转时,重定向到登录页面。在登录完成之后,在回到之前的页面。
封装一个校验路由权限并且重定向的组件。如下所示:
1 2 3 4 5 6 7 8 9 10 11 12
| export default function RequireAuth({children}) { const whiteList = ["/", "/about"]
const { pathname } = useLocation();
const notRequiredAuth = whiteList.includes(pathname);
return (hasToken || notRequiredAuth ? children : <Navigate to="/login" replace state={pathname} />) }
|
接下来我们只要使用该组件包裹我们的路由组件就好了
1 2 3
| <RequireAuth> <Link to="/list" style={{marginRight: '15px'}}>列表</Link> </RequireAuth>
|
Data Mode
react router v7 官网现在出现了3种模式,Framework Mode、Data Mode、Declarative Mode。
- Framework Mode:
- 强依赖 React Router Data APIs(loader、action、errorElement 等)
- 文件即路由:如 app/routes/dashboard.tsx 就是 /dashboard
- 默认 SSR 支持(如 Remix)
- 路由定义抽象于文件系统,不用手动写 createBrowserRouter
- Data Mode:
- 使用 createBrowserRouter 配置路由并定义 loader、action 等函数。
- 强调路由组件初始化前就完成数据加载
- Declarative Mode:
- 使用 “Routes” “Route” 等 JSX 方式声明路由,数据处理在组件内部完成。(传统模式)
Framework Mode 架构模式更适合于 SSR 应用,对于一般的管理后台,把路由根据文件来配置有点不太方便,管理后台通常有路由权限的问题,所以不建议使用此模式。
Declarative Mode 也就是传统的声明组件的方式配置路由,大部分使用过 react router 的用户都能接受,但是有点繁琐不够灵活。
Data Mode 支持配置路由的 loader、action 等,灵活性较好,可以学习这种模式,方便以后过度到架构模式
Data Mode 处理路由权限
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { Outlet } from 'react-router-dom';
export function ProtectedLayout() { return <Outlet />; }
export function authLoader() { const token = localStorage.getItem('token'); if (!token) { throw redirect('/login'); } return null; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| { path: '/', element: <RootLayout />, children: [ { element: <ProtectedLayout />, loader: authLoader, children: [ { path: 'dashboard', element: <DashboardPage />, }, { path: 'settings', element: <SettingsPage />, }, ], }, ] }
|