React学习教程,从入门到精通,React Router 语法知识点及使用方法详解(28)
React Router 语法知识点及使用方法详解
📌 当前环境说明
本文基于 React Router v5 编写(因你提供的知识点如
withRouter
、Switch
、Prompt
等属于 v5 特性)。
若使用 React Router v6,部分 API 已废弃或重构(如Switch → Routes
,withRouter → hooks
,Prompt → unstable_usePrompt
等)。
一、React Router 基础路由配置
✅ 1. 安装 React Router
npm install react-router-dom@5
✅ 2. 简单示例:网站列表(基础路由)
🎯 功能说明:
- 首页
/
显示网站列表 - 点击跳转到对应网站详情
/site/:id
- 使用
BrowserRouter
,Route
,Link
,Switch
🧩 代码示例:
// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';// 模拟数据
const sites = [{ id: 1, name: 'Google', url: 'https://google.com' },{ id: 2, name: 'GitHub', url: 'https://github.com' },{ id: 3, name: 'React', url: 'https://reactjs.org' },
];// 首页组件:显示网站列表
function Home() {return (<div><h2>🌐 网站列表</h2><ul>{sites.map(site => (<li key={site.id}>{/* 使用 Link 进行客户端导航,不刷新页面 */}<Link to={`/site/${site.id}`}>{site.name}</Link></li>))}</ul></div>);
}// 详情页组件:根据 URL 参数显示网站信息
function SiteDetail({ match }) {// match.params.id 获取动态路由参数const site = sites.find(s => s.id === parseInt(match.params.id));if (!site) return <h3>网站不存在</h3>;return (<div><h2>📌 {site.name} 详情页</h2><p>网址:<a href={site.url} target="_blank" rel="noopener noreferrer">{site.url}</a></p><Link to="/">⬅ 返回首页</Link></div>);
}// 主应用组件
function App() {return (<Router><div style={{ padding: '20px' }}><h1>🔗 React Router 网站导航系统</h1><hr />{/* Switch 确保只匹配第一个符合条件的路由 */}<Switch>{/* 精确匹配首页 */}<Route exact path="/" component={Home} />{/* 动态路由匹配详情页 */}<Route path="/site/:id" component={SiteDetail} />{/* 404 页面 */}<Route><h3>⛔ 页面未找到</h3><Link to="/">返回首页</Link></Route></Switch></div></Router>);
}export default App;
二、路由组件的属性(props)
当组件通过 Route
渲染时,会自动注入以下 props:
history
:用于编程式导航(如history.push()
)location
:当前 URL 信息(如pathname
,search
,state
)match
:匹配信息(如params
,path
,url
)
🧩 示例:打印路由属性
function DebugRoute({ history, location, match }) {return (<div><h3>🔍 路由调试信息</h3><pre>{JSON.stringify({ history: 'object', location, match }, null, 2)}</pre></div>);
}// 在路由中使用
<Route path="/debug" component={DebugRoute} />
三、Switch 组件
Switch
只渲染第一个匹配的Route
或Redirect
,避免多个路由同时激活。
🧩 示例:不使用 Switch 的问题
{/* ❌ 不使用 Switch —— 可能多个组件同时渲染 */}
<Route path="/" component={Home} />
<Route path="/about" component={About} />
{/* 当访问 /about 时,两个都会匹配(因为 / 包含在 /about 中)*/}
✅ 正确用法:
<Switch><Route exact path="/" component={Home} /><Route path="/about" component={About} /><Route path="/contact" component={Contact} />{/* 默认 fallback */}<Route component={NotFound} />
</Switch>
四、路由匹配 matchPath()
用于在组件外或逻辑中手动匹配路径(如在 Redux 中判断当前路由)。
🧩 语法:
import { matchPath } from 'react-router-dom';const match = matchPath("/users/123", {path: "/users/:id",exact: true,strict: false
});
🧩 示例:在组件外判断路由
import { matchPath } from 'react-router-dom';function App() {const currentPath = window.location.pathname;const userMatch = matchPath(currentPath, {path: "/user/:id",exact: true});if (userMatch) {console.log("当前是用户页,ID:", userMatch.params.id);}return (<Router>{/* ... */}</Router>);
}
五、静态路由 vs 动态路由
✅ 静态路由
路径固定,无参数。
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
✅ 动态路由
路径含参数,如 :id
, :name
。
<Route path="/user/:id" component={UserProfile} />
<Route path="/category/:categoryName" component={CategoryPage} />
🧩 示例:动态路由 + 参数获取
function UserProfile({ match }) {const { id } = match.params;return <h2>用户ID:{id}</h2>;
}// 支持多个参数
<Route path="/post/:year/:month/:slug" component={BlogPost} />function BlogPost({ match }) {const { year, month, slug } = match.params;return (<div><h2>文章:{slug}</h2><p>发布于 {year} 年 {month} 月</p></div>);
}
六、各种路由器(Routers)
✅ 1. BrowserRouter(最常用)
使用 HTML5 History API(pushState
, replaceState
),URL 看起来干净:http://example.com/about
import { BrowserRouter } from 'react-router-dom';<BrowserRouter><App />
</BrowserRouter>
✅ 2. HashRouter
使用 URL hash(#
),兼容老浏览器,URL 如:http://example.com/#/about
import { HashRouter } from 'react-router-dom';<HashRouter><App />
</HashRouter>
✅ 3. MemoryRouter
用于测试或非浏览器环境(如 React Native 之外的场景),URL 不反映在地址栏。
import { MemoryRouter } from 'react-router-dom';<MemoryRouter initialEntries={['/home', '/about']} initialIndex={0}><App />
</MemoryRouter>
✅ 4. NativeRouter(React Native 专用)
用于 React Native 应用,不在 Web 环境使用。
// 仅在 React Native 中
import { NativeRouter } from 'react-router-native';
✅ 5. StaticRouter(服务端渲染 SSR)
用于 Node.js 服务端渲染,需传入 location
和 context
。
// server.js (Express 示例)
import { StaticRouter } from 'react-router-dom';app.get('*', (req, res) => {const context = {};const markup = ReactDOMServer.renderToString(<StaticRouter location={req.url} context={context}><App /></StaticRouter>);if (context.url) {res.redirect(301, context.url);} else {res.send(`<!DOCTYPE html><html><body><div id="root">${markup}</div><script src="/client.js"></script></body></html>`);}
});
七、React Router 特性组件
✅ 1. Prompt 组件 —— 离开页面确认
在用户离开当前页面前弹出确认框(如表单未保存)。
import { Prompt } from 'react-router-dom';function ContactForm() {const [isBlocking, setIsBlocking] = useState(false);return (<div>{/* 当 isBlocking 为 true 时,离开页面会弹出提示 */}<Promptwhen={isBlocking}message="你有未保存的内容,确定要离开吗?"/><textareaonChange={(e) => setIsBlocking(e.target.value.length > 0)}placeholder="输入内容..."/><button onClick={() => setIsBlocking(false)}>提交</button></div>);
}
⚠️ 注意:现代浏览器对
Prompt
限制较多,部分浏览器可能忽略自定义消息。
✅ 2. withRouter 高阶组件(HOC)
将
history
,location
,match
注入到非路由组件中。
import { withRouter } from 'react-router-dom';function BackButton({ history }) {return (<button onClick={() => history.goBack()}>⬅ 返回上一页</button>);
}// 包装后即可获得路由属性
export default withRouter(BackButton);
在类组件中使用:
class UserProfile extends React.Component {handleEdit = () => {this.props.history.push(`/user/${this.props.match.params.id}/edit`);};render() {return (<div><h2>用户页</h2><button onClick={this.handleEdit}>编辑</button></div>);}
}export default withRouter(UserProfile);
💡 v6 替代方案:使用
useNavigate
,useLocation
,useParams
hooks。
✅ 3. Redirect 组件 —— 重定向
用于登录跳转、页面迁移、权限控制等。
基本用法:
<Redirect to="/login" />
带状态跳转:
<Redirectto={{pathname: "/login",state: { from: props.location } // 传递来源页,登录后可跳回}}
/>
条件重定向示例:
function PrivateRoute({ component: Component, isAuthenticated, ...rest }) {return (<Route{...rest}render={props =>isAuthenticated ? (<Component {...props} />) : (<Redirect to={{ pathname: "/login", state: { from: props.location } }} />)}/>);
}// 使用
<PrivateRoute path="/dashboard" component={Dashboard} isAuthenticated={userLoggedIn} />
八、综合性案例:带权限控制的后台管理系统
// App.js - 综合案例
import React, { useState } from 'react';
import {BrowserRouter as Router,Route,Link,Switch,Redirect,Prompt,withRouter
} from 'react-router-dom';// 模拟登录状态
const fakeAuth = {isAuthenticated: false,authenticate(cb) {fakeAuth.isAuthenticated = true;setTimeout(cb, 100); // 模拟异步},signout(cb) {fakeAuth.isAuthenticated = false;setTimeout(cb, 100);}
};// 登录页
function Login({ history }) {const [redirectToReferrer, setRedirectToReferrer] = useState(false);const login = () => {fakeAuth.authenticate(() => {setRedirectToReferrer(true);});};if (redirectToReferrer) {return <Redirect to="/dashboard" />;}return (<div><h2>🔒 登录</h2><button onClick={login}>登录系统</button></div>);
}// 仪表盘(需登录)
function Dashboard() {const [formChanged, setFormChanged] = useState(false);return (<div><h2>📊 仪表盘</h2><Promptwhen={formChanged}message="有未保存的更改,确定离开?"/><p>模拟表单:</p><input type="text" onChange={() => setFormChanged(true)} /><button onClick={() => setFormChanged(false)}>保存</button></div>);
}// 设置页
function Settings() {return <h2>⚙️ 设置页面</h2>;
}// 导航栏(使用 withRouter 获取 history)
const Navigation = withRouter(({ history, location }) => (<nav><ul style={{ display: 'flex', gap: '1rem', marginBottom: '1rem' }}><li><Link to="/dashboard">仪表盘</Link></li><li><Link to="/settings">设置</Link></li><li>{fakeAuth.isAuthenticated ? (<button onClick={() => {fakeAuth.signout(() => history.push('/'));}}>退出登录</button>) : (<Link to="/login">登录</Link>)}</li></ul><p>📍 当前路径:{location.pathname}</p></nav>
));// 私有路由组件
function PrivateRoute({ component: Component, ...rest }) {return (<Route{...rest}render={props =>fakeAuth.isAuthenticated ? (<Component {...props} />) : (<Redirectto={{pathname: "/login",state: { from: props.location }}}/>)}/>);
}// 主应用
function App() {return (<Router><div style={{ padding: '20px' }}><h1>🔐 后台管理系统</h1><Navigation /><Switch><Route exact path="/" render={() => <h2>欢迎!请登录进入系统</h2>} /><Route path="/login" component={Login} /><PrivateRoute path="/dashboard" component={Dashboard} /><PrivateRoute path="/settings" component={Settings} /><Route render={() => <h3>⛔ 404 页面不存在</h3>} /></Switch></div></Router>);
}export default App;
九、本章小结
知识点 | 作用说明 |
---|---|
BrowserRouter | 使用 HTML5 History API,推荐用于现代 Web 应用 |
Route | 定义路径与组件映射关系 |
Link | 声明式导航,替代 <a> 标签 |
Switch | 只渲染第一个匹配路由,避免冲突 |
match.params | 获取动态路由参数(如 /user/:id ) |
Redirect | 重定向到其他路由,常用于登录跳转 |
Prompt | 离开页面前确认,防止数据丢失 |
withRouter | 非路由组件获取路由属性(v5),v6 用 hooks 替代 |
matchPath | 手动匹配路径,适用于逻辑判断 |
HashRouter | 兼容老浏览器,URL 含 # |
StaticRouter | 服务端渲染专用 |
🚀 升级建议(React Router v6)
若你计划使用 v6,请注意:
Switch
→Routes
Route component
→Route element={<Component />}
withRouter
→useNavigate()
,useLocation()
,useParams()
Prompt
→unstable_usePrompt
(实验性)或自定义逻辑exact
属性默认启用
✅ 以上内容涵盖 React Router v5 核心知识点 + 详细案例 + 综合实战,可直接用于项目开发或学习参考。