React 路由:基础与高级特性详解
1. URL 路由基础
URL 路由是一种通过操作浏览器的 URL 来实现导航的技术,它无需向服务器发送 HTTP 请求。在 Web 应用中,核心的路由功能通常由
BrowserRouter
或
HashRouter
组件提供。
1.1 选择和配置路由组件
在导入时,这两个组件通常被命名为
Router
,示例代码如下:
import { BrowserRouter as Router, Link, Switch, Route, Redirect }
from "react-router-dom";
1.2 BrowserRouter 组件
BrowserRouter
使用 HTML5 History API,能提供自然的路由 URL,例如
http://localhost:3000/products
。该组件可以接受一系列的属性来配置其行为,详细属性如下表所示:
| 属性名 | 描述 |
| ---- | ---- |
| basename | 当应用程序不在其 URL 的根目录时使用,例如
http://localhost:3000/myapp
|
| getUserConfirmation | 用于指定获取用户对导航确认的函数,与
Prompt
组件配合使用 |
| forceRefresh | 当值为
true
时,导航时会强制进行完全刷新并向服务器发送 HTTP 请求,通常仅用于测试或浏览器不支持 History API 的情况 |
| keyLength | 每次导航更改都会有一个唯一的键,此属性用于指定键的长度,默认值为 6 个字符 |
| history | 允许使用自定义的历史对象 |
1.3 HashRouter 组件
对于不支持 History API 的旧浏览器,导航信息需要作为 URL 片段添加到 URL 末尾,即
#
字符之后。
HashRouter
组件提供了基于 URL 片段的路由功能,使用示例如下:
import React, { Component } from "react";
import { HashRouter as Router, NavLink, Route, Switch, Redirect }
from "react-router-dom";
import { ProductDisplay } from "./ProductDisplay";
import { SupplierDisplay } from "./SupplierDisplay";
export class Selector extends Component {
// ...methods omitted for brevity...
}
使用
as
关键字导入路由组件,只需更改导入语句。保存文件更改后,导航到
http://localhost:3000
,可以看到 URL 样式发生了变化。
HashRouter
组件也可以通过一些属性进行配置,具体如下表:
| 属性名 | 描述 |
| ---- | ---- |
| basename | 当应用程序不在其 URL 的根目录时使用,例如
http://localhost:3000/myapp
|
| getUserConfirmation | 用于指定获取用户对导航确认的函数,与
Prompt
组件配合使用 |
| hashType | 设置 URL 中路由编码的样式,可选值有
slash
、
noslash
和
hashbang
|
2. 高级 URL 路由特性
高级 URL 路由特性为 React 应用提供了更强大的路由控制能力,下面详细介绍这些特性。
2.1 准备工作
在使用高级路由特性之前,需要将应用程序使用的路由器从
HashRouter
更改为
BrowserRouter
,并简化
Link
和
Router
组件,示例代码如下:
import React, { Component } from "react";
import { BrowserRouter as Router, NavLink, Route, Switch, Redirect }
from "react-router-dom";
import { ProductDisplay } from "./ProductDisplay";
import { SupplierDisplay } from "./SupplierDisplay";
export class Selector extends Component {
render() {
return <Router>
<div className="container-fluid">
<div className="row">
<div className="col-2">
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/products">Products</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/suppliers">Suppliers</NavLink>
</div>
<div className="col">
<Switch>
<Route path="/products" component={ ProductDisplay} />
<Route path="/suppliers" component={ SupplierDisplay } />
<Redirect to="/products" />
</Switch>
</div>
</div>
</div>
</Router>
}
}
完成上述更改后,在命令提示符中导航到项目文件夹,并运行以下命令启动开发工具:
npm start
2.2 创建路由感知组件
当
Route
组件显示一个组件时,会为其提供描述当前路由的上下文数据以及用于导航的 API,使组件能够感知当前位置并参与路由。当使用
component
属性时,
Route
会将数据和 API 作为
match
、
location
和
history
属性传递给显示的组件;当使用
render
属性时,渲染函数会接收到一个包含
match
、
location
和
history
属性的对象。这些对象的详细描述如下表所示:
| 属性名 | 描述 |
| ---- | ---- |
| match | 提供
Route
组件如何匹配当前浏览器 URL 的信息 |
| location | 提供当前位置的表示,可用于导航而无需使用字符串形式的 URL |
| history | 提供用于导航的 API |
2.3 理解 match 属性
match
属性为组件提供了父
Route
如何匹配当前 URL 的详细信息。其包含的属性如下表所示:
| 属性名 | 描述 |
| ---- | ---- |
| url | 返回
Route
匹配的 URL |
| path | 返回用于匹配 URL 的路径值 |
| params | 返回路由参数,允许将 URL 段映射到变量 |
| isExact | 如果路由路径与 URL 完全匹配,则返回
true
|
为了演示路由属性的使用,创建了一个
RouteInfo
组件,代码如下:
import React, { Component } from "react";
export class RouteInfo extends Component {
renderTable(title, prop, propertyNames) {
return <React.Fragment>
<tr><th colSpan="2" className="text-center">{ title }</th></tr>
{ propertyNames.map(p =>
<tr key={p }>
<td>{ p }</td>
<td>{ JSON.stringify(prop[p]) }</td>
</tr>)
}
</React.Fragment>
}
render() {
return <div className="bg-info m-2 p-2">
<h4 className="text-white text-center">Route Info</h4>
<table className="table table-sm table-striped bg-light">
<tbody>
{ this.renderTable("Match", this.props.match,
["url", "path", "params", "isExact"] )}
</tbody>
</table>
</div>
}
}
在
Selector
组件中添加导航链接和对应的
Route
,代码如下:
import React, { Component } from "react";
import { BrowserRouter as Router, NavLink, Route, Switch, Redirect }
from "react-router-dom";
import { ProductDisplay } from "./ProductDisplay";
import { SupplierDisplay } from "./SupplierDisplay";
import { RouteInfo } from "./routing/RouteInfo";
export class Selector extends Component {
render() {
return <Router>
<div className="container-fluid">
<div className="row">
<div className="col-2">
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/products">Products</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/suppliers">Suppliers</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active" to="/info">Route Info</NavLink>
</div>
<div className="col">
<Switch>
<Route path="/products" component={ ProductDisplay} />
<Route path="/suppliers" component={ SupplierDisplay } />
<Route path="/info" component={ RouteInfo } />
<Redirect to="/products" />
</Switch>
</div>
</div>
</div>
</Router>
}
}
保存更改后,点击
Route Info
链接,即可看到
match
属性的详细信息。
2.4 理解 location 属性
location
对象用于描述导航位置,作为属性提供时,它描述了当前位置。其包含的属性如下表所示:
| 属性名 | 描述 |
| ---- | ---- |
| key | 返回标识位置的键 |
| pathname | 返回位置的路径 |
| search | 返回位置 URL 的搜索项(即 URL 中
?
字符后面的部分) |
| hash | 返回位置 URL 的 URL 片段(即
#
字符后面的部分) |
| state | 用于将任意数据与位置关联 |
在
RouteInfo
组件中添加
location
属性的显示,并使用
location
对象作为
Link
组件的导航目标,代码如下:
import React, { Component } from "react";
import { Link } from "react-router-dom";
export class RouteInfo extends Component {
renderTable(title, prop, propertyNames) {
return <React.Fragment>
<tr><th colSpan="2" className="text-center">{ title }</th></tr>
{ propertyNames.map(p =>
<tr key={p }>
<td>{ p }</td>
<td>{ JSON.stringify(prop[p]) }</td>
</tr>)
}
</React.Fragment>
}
render() {
return <div className="bg-info m-2 p-2">
<h4 className="text-white text-center">Route Info</h4>
<table className="table table-sm table-striped bg-light">
<tbody>
{ this.renderTable("Match", this.props.match,
["url", "path", "params", "isExact"] )}
{ this.renderTable("Location", this.props.location,
["key", "pathname", "search", "hash", "state"] )}
</tbody>
</table>
<div className="text-center m-2 bg-light">
<Link className="btn btn-primary m-2"
to={ this.props.location }>Location</Link>
</div>
</div>
}
}
2.5 使用 URL 参数
当组件感知到 URL 路由系统时,通常需要根据当前 URL 调整其行为。React-Router 包支持 URL 参数,允许将 URL 段的内容分配给变量,组件可以读取这些变量而无需解析 URL 或了解其结构。以下是添加包含 URL 参数的
Route
和目标
Link
组件的示例代码:
import React, { Component } from "react";
import { BrowserRouter as Router, NavLink, Route, Switch, Redirect }
from "react-router-dom";
import { ProductDisplay } from "./ProductDisplay";
import { SupplierDisplay } from "./SupplierDisplay";
import { RouteInfo } from "./routing/RouteInfo";
export class Selector extends Component {
render() {
return <Router>
<div className="container-fluid">
<div className="row">
<div className="col-2">
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/products">Products</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/suppliers">Suppliers</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/info/match">Match</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/info/location">Location</NavLink>
</div>
<div className="col">
<Switch>
<Route path="/products" component={ ProductDisplay} />
<Route path="/suppliers" component={ SupplierDisplay } />
<Route path="/info/:datatype" component={ RouteInfo } />
<Redirect to="/products" />
</Switch>
</div>
</div>
</div>
</Router>
}
}
URL 参数通过在路径属性段前加冒号(
:
)来指定。当
Route
匹配 URL 时,会将相应的 URL 段值分配给参数,并通过
match
属性的
params
属性传递给组件。
更新
RouteInfo
组件以使用 URL 参数选择要呈现给用户的上下文数据,代码如下:
import React, { Component } from "react";
import { Link } from "react-router-dom";
export class RouteInfo extends Component {
renderTable(title, prop, propertyNames) {
return <React.Fragment>
<tr><th colSpan="2" className="text-center">{ title }</th></tr>
{ propertyNames.map(p =>
<tr key={p }>
<td>{ p }</td>
<td>{ JSON.stringify(prop[p]) }</td>
</tr>)
}
</React.Fragment>
}
render() {
return <div className="bg-info m-2 p-2">
<h4 className="text-white text-center">Route Info</h4>
<table className="table table-sm table-striped bg-light">
<tbody>
{ this.props.match.params.datatype ==="match"
&& this.renderTable("Match", this.props.match,
["url", "path", "params", "isExact"] )}
{ this.props.match.params.datatype === "location"
&& this.renderTable("Location", this.props.location,
["key", "pathname", "search", "hash", "state"] )}
</tbody>
</table>
<div className="text-center m-2 bg-light">
<Link className="btn btn-primary m-2"
to={ this.props.location }>Location</Link>
</div>
</div>
}
}
URL 参数不仅是组件接收 URL 段内容的便捷方式,还能将 URL 的结构与目标组件解耦,允许更改 URL 结构或使用多个 URL 指向相同内容而无需修改组件代码。组件只需知道所需的 URL 参数名称,而无需了解它们在 URL 中的具体位置。
2.6 URL 参数的优势及应用场景
URL 参数具有显著的优势,其不仅是组件接收 URL 段内容的便捷途径,还能将 URL 的结构与目标组件进行解耦。这意味着可以对 URL 的结构进行修改,或者让多个 URL 指向相同的内容,而无需对组件代码进行修改。
以下是 URL 参数的优势及应用场景的详细说明:
-
解耦 URL 结构与组件
:组件只需关注所需的 URL 参数名称,而无需了解这些参数在 URL 中的具体位置。例如,在前面的
RouteInfo
组件中,它依赖于
datatype
URL 参数,但并不依赖于该参数在 URL 中的具体位置。这使得组件可以适配不同的路径,如
/info/:datatype
或
/diagnostics/routing/:datatype
,而无需修改代码。
-
多 URL 指向相同内容
:可以使用多个不同的 URL 来访问相同的内容,而无需修改组件。例如,可以同时使用
/info/match
和
/diagnostics/routing/match
来访问相同的信息,只需确保 URL 参数名称一致即可。
-
简化组件逻辑
:组件可以直接通过 URL 参数获取所需的数据,而无需解析整个 URL。这简化了组件的逻辑,提高了代码的可读性和可维护性。
2.7 高级路由特性的总结
高级 URL 路由特性为 React 应用提供了更强大的路由控制能力,使组件能够更好地感知和参与路由过程。以下是对这些特性的总结:
| 特性 | 描述 |
| ---- | ---- |
| 创建路由感知组件 | 通过
Route
组件提供的
match
、
location
和
history
属性,组件可以感知当前路由信息并参与导航 |
| 理解
match
属性 |
match
属性提供了
Route
组件如何匹配当前 URL 的详细信息,包括匹配的 URL、路径、参数和是否完全匹配等 |
| 理解
location
属性 |
location
对象描述了当前导航位置,包括键、路径名、搜索项、哈希值和关联的数据等 |
| 使用 URL 参数 | URL 参数允许将 URL 段的内容分配给变量,组件可以直接读取这些变量,而无需解析 URL 或了解其结构 |
3. 路由的实际应用与流程
3.1 路由配置流程
在实际应用中,配置路由通常遵循以下步骤:
1.
导入路由组件
:从
react-router-dom
中导入所需的路由组件,如
BrowserRouter
、
NavLink
、
Route
、
Switch
和
Redirect
。
2.
定义路由结构
:在组件中定义路由的结构,包括导航链接和对应的路由规则。
3.
配置路由参数
:如果需要使用 URL 参数,在路由路径中添加参数,并在组件中使用这些参数。
4.
渲染路由组件
:将路由组件渲染到应用中,确保路由功能正常工作。
以下是一个完整的路由配置示例:
import React, { Component } from "react";
import { BrowserRouter as Router, NavLink, Route, Switch, Redirect }
from "react-router-dom";
import { ProductDisplay } from "./ProductDisplay";
import { SupplierDisplay } from "./SupplierDisplay";
import { RouteInfo } from "./routing/RouteInfo";
export class Selector extends Component {
render() {
return (
<Router>
<div className="container-fluid">
<div className="row">
<div className="col-2">
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/products">Products</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/suppliers">Suppliers</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/info/match">Match</NavLink>
<NavLink className="m-2 btn btn-block btn-primary"
activeClassName="active"
to="/info/location">Location</NavLink>
</div>
<div className="col">
<Switch>
<Route path="/products" component={ProductDisplay} />
<Route path="/suppliers" component={SupplierDisplay} />
<Route path="/info/:datatype" component={RouteInfo} />
<Redirect to="/products" />
</Switch>
</div>
</div>
</div>
</Router>
);
}
}
3.2 路由导航流程
当用户进行导航时,路由系统会按照以下流程进行处理:
graph TD;
A[用户点击导航链接] --> B[路由系统捕获 URL 变化];
B --> C[根据路由规则匹配 URL];
C --> D{是否匹配成功};
D -- 是 --> E[渲染对应的组件];
D -- 否 --> F[执行重定向或显示错误信息];
具体步骤如下:
1.
用户点击导航链接
:用户在应用中点击导航链接,触发 URL 的变化。
2.
路由系统捕获 URL 变化
:路由系统会监测到 URL 的变化,并开始处理导航请求。
3.
根据路由规则匹配 URL
:路由系统会根据预先定义的路由规则,尝试匹配当前的 URL。
4.
判断是否匹配成功
:如果匹配成功,路由系统会渲染对应的组件;如果匹配失败,会执行重定向或显示错误信息。
5.
渲染组件或执行重定向
:如果匹配成功,路由系统会将对应的组件渲染到页面上;如果匹配失败,会根据重定向规则跳转到指定的页面。
4. 总结
通过本文的介绍,我们了解了 React 中 URL 路由的基础和高级特性。基础部分介绍了
BrowserRouter
和
HashRouter
组件的使用和配置,以及如何通过路由实现导航。高级部分则深入探讨了路由感知组件、
match
和
location
属性、URL 参数等特性,使组件能够更好地感知和参与路由过程。
在实际应用中,合理使用这些路由特性可以提高应用的可维护性和用户体验。通过 URL 参数,可以将 URL 的结构与组件解耦,使组件更加灵活和可复用。同时,了解路由的配置和导航流程,可以帮助我们更好地设计和实现复杂的路由系统。
希望本文能够帮助你更好地理解和应用 React 中的 URL 路由,提升你的开发技能和应用质量。
超级会员免费看
519

被折叠的 条评论
为什么被折叠?



