三、管理用户交互
在本章中,我们将学习如何管理用户与基于 React 的用户界面组件交互时生成的事件。我们将探索 React 组件生命周期中触发的事件,并将学习如何利用这些事件来创建高效组件。最后,我们将使用 React Router 库在组件实现的不同视图之间进行轻松导航。
在本章结束时,您将能够:
- 处理由用户交互生成的事件
- 在事件触发时更改组件的状态
- 使用组件的生命周期事件获得更好的用户体验
- 配置路由以允许通过组件 进行导航
管理用户交互
任何 web 应用程序都需要用户与用户界面(用户界面之间进行交互。没有交互的应用程序不是真正的应用程序;交互性是一项基本要求。
我们在上一章中构建的应用程序不允许交互。它只是显示数据,用户不能用它做任何事情(除了查看数据)。
假设我们想在上一章中开始构建的目录应用程序中引入一些交互。例如,我们可能希望在用户单击产品区域时显示产品价格警报。
前提是产品数据包括价格,如以下 JSON 对象所示:
[
{"code":"P01",
"name": "Traditional Merlot",
"description": "A bottle of middle weight wine, lower in tannins
(smoother), with a more red-fruited flavor profile.",
"price": 4.5, "selected": false},
{"code":"P02",
"name": "Classic Chianti",
"description": "A medium-bodied wine characterized by a marvelous
freshness with a lingering, fruity finish",
"price": 5.3, "selected": false},
{"code":"P03",
"name": "Chardonnay",
"description": "A dry full-bodied white wine with spicy,
bourbon-y notes in an elegant bottle",
"price": 4.0, "selected": false},
{"code":"P04",
"name": "Brunello di Montalcino",
"description": "A bottle of red wine with exceptionally bold fruit
flavors, high tannin, and high acidity",
"price": 7.5, "selected": false}
]
我们可以按如下方式实现此行为:
import React from 'react';
class Product extends React.Component {
showPrice() {
alert(this.props.item.price);
}
render() {
return <li onClick={() => this.showPrice()}>
<h3>{this.props.item.name}</h3>
<p>{this.props.item.description}</p>
</li>;
}
}
export default Product;
让我们分析组件的代码,并突出显示与以前版本的差异。
首先,我们添加了showPrice()
方法,通过一个预警显示当前产品实例的价格。此方法在分配给<li>
标记的onClick
属性的箭头函数中调用。
这些简单的更改允许Product
组件捕获click
事件并执行showPrice()
方法。
我们现在将打开现有项目my-shop-01
,以显示先前代码更改的结果:
- 打开控制台窗口
- 移动到
my-shop-01
文件夹 - 运行
npm install
- 运行
npm start
单击产品的结果显示在以下屏幕截图中:
HTML 事件与 React 事件
正如我们所看到的,React 处理事件的方法与 HTML 中的经典事件管理非常相似。然而,有一些细微的差异需要考虑。
HTML 事件使用小写字母命名,而 JSX 事件使用 camelCase。例如,在 HTML 中,应使用以下语法:
<li onclick="...">...</li>
但在 JSX 中,您使用以下语法:
<li onClick=...>...</li>
在 HTML 中,分配一个表示函数调用的字符串,而在 JSX 中,分配一个函数,如下所示:
<li onclick="showPrice()">...</li>
<li onClick={showPrice}>...</li>
当然,您可以指定任何返回或表示函数的 JavaScript 表达式,如以下示例所示:
<li onClick={() => this.showPrice()}>
最后,您可以通过返回false
来防止大多数 HTML 事件的默认行为,而在 JSX 事件中,您需要显式调用preventDefault
。以下是一个典型示例:
<a href="#" onClick={(e) => { e.preventDefault();
console.log("Clicked");}}>Click</a>
事件处理程序和 this 关键字
在前面定义Product
组件的示例中,我们将箭头函数指定给onClick
属性,而不是简单的showPrice()
方法。这不仅仅是偏好的问题。这是必要的,因为我们在showPrice()
方法中使用了this
关键字。
事实上,当事件处理程序执行时,this
关键字不再绑定到Product
类,因为它是在不同的上下文中异步执行的。这种行为并不取决于 React,而是取决于 JavaScript 的工作方式。
为了将该方法绑定到当前类,我们有几个选项:
- 使用 arrow 函数并在其主体内调用该方法,如以下示例所示:
<li onClick={() => this.showPrice()}>
- 使用
bind()
方法将该方法绑定到当前类上下文,如下例所示:
<li onClick={this.showPrice.bind(this)}>
- 将方法分配给事件属性时,可以在类构造函数中使用
bind()
,而不是内联使用它。以下是该方法的一个示例:
constructor() {
this.showPrice = this.showPrice.bind(this);
}
...
<li onClick={this.showPrice}>
改变状态
我们看到的事件管理示例非常简单,但它只显示了 React 事件管理的基础知识。此示例不涉及状态,其管理非常简单。在许多实际情况下,事件会导致应用程序状态的更改,这意味着组件状态的更改。
例如,假设您希望允许从目录中选择产品。为此,我们将selected
属性添加到每个产品对象中,如以下数组所示:
[
{"code":"P01",
"name": "Traditional Merlot",
"description": "A bottle of middle weight wine, lower in tannins
(smoother), with a more red-fruited flavor profile.",
"price": 4.5, "selected": false},
{"code":"P02",
"name": "Classic Chianti",
"description": "A medium-bodied wine characterized by a marvelous
freshness with a lingering, fruity finish",
"price": 5.3, "selected": false},
{"code":"P03",
"name": "Chardonnay",
"description": "A dry full-bodied white wine with spicy, bourbon-y
notes in an elegant bottle",
"price": 4.0, "selected": false},
{"code":"P04",
"name": "Brunello di Montalcino",
"description": "A bottle of red wine with exceptionally bold fruit
flavors, high tannin, and high acidity",
"price": 7.5, "selected": false}
]
当用户单击产品区域时,selected
属性的值被切换,并且区域的背景颜色发生变化。下面的代码片段显示了Product
组件的新版本:
import React from 'react';
import './Product.css'
class Product extends React.Component {
select() {
this.props.item.selected = !this.props.item.selected;
}
render() {
let classToApply = this.props.item.selected? "selected": "";
return <li onClick={() => this.select()} className={classToApply}>
<h3>{this.props.item.name}</h3>
<p>{this.props.item.description}</p>
</li>;
}
}
export default Product;
select()
方法切换selected
属性的值,而在 rendering 方法中,我们根据selected
属性的值计算要应用的类的名称。然后将生成的类名分配给className
属性。
出乎意料的是,此代码无法正常工作。您可以通过执行以下步骤进行验证。我们可以打开现有项目my-shop-02
,以查看前面代码的结果。遵循以下步骤:
- 打开控制台窗口
- 移动到
my-shop-02
文件夹 - 运行
npm install
- 运行
npm start
The code is not working as expected because the select()
method does not change the component's state, so the render()
method is not triggered. In addition, keep in mind that the props
property is read-only, so any change to it has no effect.
Product
组件是一个无状态的组件,因此我们在这里没有要更改的状态。产品数据通过props
来自Catalog
根组件。那么,我们如何从Product
组件实例触发的事件开始改变Catalog
组件的状态呢?
具体来说,子组件如何更改其父组件的状态?
实际上,子组件没有机会更改父组件的状态,因为在 React 组件层次结构中,数据以单向方式从父组件流向子组件。我们在下图中说明了此流程:
我们无法将数据从子级推送到父级。为了让子组件更改父组件的状态,我们需要获得一个方法来处理该状态。由于组件状态只能由组件本身访问,因此父组件必须通过props
属性向其子组件提供该方法。
考虑下面的代码:
import React from 'react';
import './Catalog.css';
import ProductList from './ProductList';
class Catalog extends React.Component {
constructor() {
super();
this.state = { products: [] };
fetch("products.json")
.then(response => response.json())
.then(json => {this.setState({products: json})})
.catch(error => console.log(error));
}
select(productCode) {
let productList = this.state.products.map(function(p) {
if (p.code === productCode) {
p.selected = (!p.selected);
}
return p;
});
this.setState({products: productList});
}
render() {
return <div><h2>Wine Catalog</h2><ProductList
items={this.state.products} selectHandler={this.select}/></div>;
}
}
export default Catalog;
前面的代码将select()
方法添加到Catalog
组件中。此方法将产品代码作为输入参数,从组件的状态获取产品列表,并更新相应产品的selected
属性。然后用新产品列表更新组件的状态。
select()
方法被分配给ProductList
标记中的新selectHandler
属性,因此相应组件可以通过props
属性访问它。
下面的代码显示了如何通过selectHandler
属性将this.props.selectHandler
从ProductList
组件传递到Product
组件:
import React from 'react';
import './ProductList.css';
import Product from './Product';
class ProductList extends React.Component {
render() {
let products = [];
for (let product of this.props.items) {
products.push(<Product item={product}
selectHandler={this.props.selectHandler}/>);
}
return <ul>{products}</ul>;
}
}
export default ProductList;
最后,Product
组件通过调用通过this.props.selectHandler
属性传递的具有适当产品代码的select()
方法来处理onClick
事件:
import React from 'react';
import './Product.css'
class Product extends React.Component {
render() {
let classToApply = this.props.item.selected? "selected": "";
return <li onClick={() => this.props.selectHandler
(this.props.item.code)} className={classToApply}>
<h3>{this.props.item.name}</h3>
<p>{this.props.item.description}</p>
</li>
}
}
export default Product;
我们现在将打开现有的项目my-shop-03
,以便查看前面代码的结果。遵循以下步骤:
- 打开控制台窗口
- 移动到
my-shop-03
文件夹 - 运行
npm install
- 运行
npm start
我们可以得出结论,子组件上的事件会触发通过props
传递的父组件方法的执行。该方法改变了父对象的状态,该改变的效果通过props
再次传播给子对象。下图说明了此行为:
活动:将项目添加到购物车
场景
我们希望允许用户通过从产品目录中挑选商品来向购物车添加商品。
瞄准
本活动的目的是熟悉 React 中的事件管理。
完成步骤
- 在 ProtoT0 席文件夹中考虑现有项目
- 处理
Product
组件的“添加到购物车”按钮的点击事件,以便将该产品添加到购物车
溶液
一种可能的解决方案是包含在Code/Chapter-3/
的my-cart-02
文件夹中的解决方案。
组件生命周期事件
在 React 应用程序中,根据运行时应用程序的演变动态创建组件。用户的交互开始组件的创建、可视化、屏幕上的更新和销毁。
因此,组件在应用程序执行期间会经历不同的阶段:这些阶段代表它们的生命周期。
React 允许我们以定制的方式拦截和管理组件生命周期的各个阶段,这得益于我们可以通过实现特定方法来处理的一组事件。
在分析组件的生命周期事件之前,我们应该强调创建组件的第一步是执行其构造函数。虽然这不是 React 的生命周期阶段之一,但它是组件生命周期的第一步。在组件的构造函数执行期间,DOM 不可用,并且不可能访问任何子组件。构造函数执行是执行与图形呈现或子操作无关的初始化的正确时机。
创建组件后,React 将触发与组件生命周期的各个阶段相对应的一些事件。我们可以捕获这些事件,并通过在组件中实现一些方法来处理它们。考虑以下方法:
componentWillMount
当组件即将插入 DOM 时,将执行此方法。在初始呈现发生之前,将调用此方法一次。通常,此方法用于执行不涉及 DOM 的组件的任何初始化,例如初始化组件属性或局部变量的值。
You can use the setState()
method within componentWillMount()
, but it will not trigger a re-render of the component, so use it carefully.
componentWillReceiveProps
是当组件通过props
从父级接收新值时,在呈现之前调用的方法。此方法接收新值作为参数,我们可以通过this.props
访问旧值。
如果我们在执行此方法期间尝试更改组件状态,我们将不会触发任何其他渲染。此外,componentWillReceiveProps()
在初始呈现时不被调用。
shouldComponentUpdate
方法应返回一个布尔值,说明是否应呈现组件(true
)或不呈现组件(false
。如果该方法返回false
,则不调用下一个方法,包括render()
。
这有两个参数:nextProps
,包含props
的新值;nextState
包含组件状态的新值。
componentWillUpdate
在render()
方法之前立即调用,因此这是在更新组件之前执行某些处理的最后机会。
You cannot use setState()
within an implementation of shouldComponentUpdate()
.
componentDidUpdate
在呈现发生后立即调用,在其执行过程中,我们可以在 DOM 中访问组件的新版本。该方法有两个参数:前一个props
和前一个状态。
componentDidMount
在组件插入 DOM 后调用,只调用一次。
在组件从 DOM 中移除之前立即调用componentWillUnmount
。
You cannot use setState()
during the execution of this method.
我们可以将组件生命周期事件分为三个主要方面:
-
挂载:该
props
组包含与 DOM 操作相关的事件:componentWillMount
、componentDidMount
和componentWillUnmount
-
道具更新:该组包含组件通过父组件传递的
props
更新时触发的事件,包括:componentWillReceiveProps
、shouldComponentUpdate
、componentWillUpdate
、componentDidUpdate
-
通过 setState 更新():在该组中,我们发现组件通过
setState()
:shouldComponentUpdate
、componentWillUpdate
、componentDidUpdate
更新时触发的事件
下图用不同的颜色展示了我们刚才讨论的三个领域的事件流程和亮点:
活动:显示添加到购物车的项目数量
场景
我们希望避免同一产品在购物车中多次出现。相反,我们希望购物车只出现一次产品及其数量,如以下屏幕截图所示:
瞄准
此活动的目的是利用 React 组件的生命周期事件。
完成步骤
- 利用在先前活动中更改的项目(或
my-cart-02
文件夹中的现有项目)。 - 更改
Cart
组件,以显示非重复产品列表及其相关出现次数。
Handle the componentWillReceiveProps
event to prepare data for the internal state of the Cart
component.
溶液
一种可能的解决方案是包含在Code/Chapter-3
的my-cart-03
文件夹中的解决方案。
管理路由
基于单页应用程序模型的现代 web 应用程序离不开路由机制,这是一种在视图之间导航的方式,同时保持在同一 HTML 页面上。
我们可以将视图视为 UI 中的占位符,在这里我们可以以独占的方式动态呈现一个组件或另一个组件。让我们用一个例子来阐明这个概念。
假设我们想在葡萄酒目录应用程序中添加一个导航栏。在其最简单的实现中,我们希望交替显示目录和 About 部分,提供有关应用程序本身的一些信息。新 UI 将如以下屏幕截图所示:
单击菜单项时,我们希望主区域发生更改,而标题保持不变。在这种情况下,主要区域将是我们显示Catalog
组件或About
组件的视图,具体取决于我们单击的菜单项。
我们如何在 React 中实现路由机制?
安装 React 路由
我们可以使用React Router在基于 React 的应用程序中启用路由,该软件包为我们提供了特定的 React 组件,允许我们建立完整的路由系统。
我们通过在应用程序文件夹中键入以下命令,在应用程序中安装该软件包:
npm install --save react-router-dom
React 路由提供三个包:
react-router
react-router-dom
react-router-native
第一个包提供了核心路由组件和功能。第二个为浏览器环境提供特定组件,第三个支持react-native
,一个将 React 组件映射到本地移动 UI 小部件的环境。react-router-dom
和react-router-native
都使用react-router
功能。
使用路由
在我们的环境中安装 React Router 包后,我们需要在应用程序中使用提供的组件。
我们需要做的第一件事是向应用程序添加路由功能。我们可以通过更改index.js
文件的代码来实现,如下所示:
import React from 'react';
...
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'));
registerServiceWorker();
我们强调了与以前版本代码的主要区别。如您所见,我们从react-router-dom
模块导入了BrowserRouter
组件,并将App
组件包装在其中。
通过包装App
组件,BrowserRouter
组件丰富了它的路由功能。
This is a component composition hence we have called this as component wrapping.
定义视图
现在,我们需要创建一个视图来显示Catalog
组件或关于页面,如以下屏幕截图所示:
我们可以通过修改App.js
代码来实现,如下所示:
import React, { Component } from 'react';
import './App.css';
import Catalog from './Catalog';
import About from './About';
import { Switch, Route } from 'react-router-dom'
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">The Catalog App</h1>
<nav>
<ul>
<li><Link to='/'>Catalog</Link></li>
<li><Link to='/about'>About</Link></li>
</ul>
</nav>
</header>
<Switch>
<Route exact path='/' component={Catalog}/>
<Route path='/about' component={About}/>
</Switch>
</div>
);
}
}
export default App;
我们从react-router-dom
模块中导入了Switch
和Route
组件,并在 JSX 表达式中使用它们,其中Catalog
元素曾经是。
Switch
组件允许我们定义一个视图,即我们将在其中切换组件的区域。Route
组件用作Switch
的子元素,它们允许我们将 URL 映射到组件。在我们的示例中,我们将根 URL(/
映射到Catalog
组件,/about
URL 映射到About
组件。这意味着当BrowserRouter
截取移动到其中一个 URL 的请求时,它将在视图中呈现适当的组件。
允许我们显示目录或有关应用程序的信息的导航栏实现如下:
import React, { Component } from 'react';
import './App.css';
import Catalog from './Catalog';
import About from './About';
import { Switch, Route, Link } from 'react-router-dom'
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">The Catalog App</h1>
<nav>
<ul>
<li><Link to='/'>Catalog</Link></li>
<li><Link to='/about'>About</Link></li>
</ul>
</nav> </header>
<Switch>
<Route exact path='/' component={Catalog}/>
<Route path='/about' component={About}/>
</Switch>
</div>
);
}
}
export default App;
在这里,我们添加了Link
组件的导入,并在突出显示的标记中使用它。Link
组件允许我们创建一个超链接元素,该元素将被BrowserRouter
组件捕获。
这些更改为我们的应用程序添加了一个可用的导航栏。通过执行以下步骤,可以看到这些更改的结果。
我们将打开现有项目my-shop-04
,以显示前面代码的结果:
- 打开控制台窗口
- 移动到
my-shop-04
文件夹 - 运行
npm install
- 运行
npm start
关于路由组件的一些注释
请注意,Route
组件具有path
属性(允许我们指定要映射的 URL)和component
属性(允许我们指定要在当前视图中渲染的组件):
<Switch>
<Route exact path='/' component={Catalog}/>
<Route path='/about' component={About}/>
</Switch>
React Router 使用path
属性来检测要渲染的组件,由相应的component
属性指定。
在前面的路由映射中,如果点击与/about
URL 关联的Link
组件,根路径为/
的路由将匹配/about
的起始部分,并呈现Catalog
组件。
When the user requests a URL by clicking on the Link
component, the list of routes is scanned in order to find a path value that matches the starting part of the URL. The first matching value determines the component to render.
如果我们想要在path
属性的值和 URL 之间进行严格的比较,我们需要指定确切的属性,如下所示:
<Switch>
<Route exact path='/' component={Catalog}/>
<Route path='/about' component={About}/>
</Switch>
这可以防止任何以/
开头的 URL 被第一条路由捕获。
Route
组件的component
属性允许我们指定要渲染的组件。或者,我们可以使用render
属性来指定调用返回 React 元素的函数,如以下示例所示:
<Route path='/about' render={() => (<About data={someData}/>)}/>
这种方法类似于使用component
属性,但在内联渲染和需要向元素传递值时,它可能很有用。
Route
组件还允许我们指定children
属性。与render
一样,我们可以将一个函数分配给该属性,但该函数返回的元素将始终呈现,无论路径是否匹配。
考虑下面的例子:
<Switch>
<Route exact path='/' component={Catalog}/>
<Route path='/about' component={About}/>
<Route path='/footer' children={() => (<Footer />)}/>
</Switch>
即使路径/footer
不匹配,Footer
组件也将始终被渲染。
嵌套视图
在前面的示例中,我们使用 React Router 提供的Switch
、Route
和Link
组件在App
组件中实现了视图导航。我们可以在任何其他组件中使用这些布线组件,以便构建嵌套视图和嵌套布线。
让我们用一个例子来说明这一点。假设我们想在应用程序中添加一个酿酒师列表。我们可以在导航栏中添加一个新项目,使我们能够导航到显示该列表的页面。
以下屏幕截图显示了新布局的显示方式:
那么,让我们更改App
组件的 JSX 标记,如下所示:
import React, { Component } from 'react';
import './App.css';
import Catalog from './Catalog';
import About from './About';
import WineMakers from './WineMakers';
import { Switch, Route, Link } from 'react-router-dom';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">The Catalog App</h1>
<nav>
<ul>
<li><Link to='/'>Catalog</Link></li>
<li><Link to='/winemakers'>WineMakers</Link></li>
<li><Link to='/about'>About</Link></li>
</ul>
</nav>
</header>
<Switch>
<Route exact path='/' component={Catalog}/>
<Route path='/winemakers' component={WineMakers}/>
<Route path='/about' component={About}/>
</Switch>
</div>
);
}
}
export default App;
我们导入了WineMakers
组件,定义了一条将/winemakers
路径映射到新组件的路径,并添加了导航到该组件的链接。
我们可以实施以下酿酒商名单:
import React from 'react';
import WineMaker from './WineMaker';
import { Switch, Route, Link } from 'react-router-dom';
class WineMakers extends React.Component {
renderWineMakersList() {
return <ul>
...
<Link to="/winemakers/WM2">Wine & Co</Link>
</li>
</ul>;
}
render() {
return <Switch>
...
export default WineMakers;
WineMakers
组件具有renderWineMakersList()
方法,该方法返回 React 元素,实现每个酿酒师的链接列表。此方法用作组件的render()
方法中与/winemakers
路径匹配的路由的render
属性值。其他路径获取指向每个特定酿酒师的路径,并根据标识符代码呈现WineMaker
组件。
您可能注意到我们正在WineMakers
组件中实现一个视图,该视图显示在App
组件中实现的视图的内部。换句话说,我们通过组合实现视图的组件来实现嵌套视图。
路径参数
WineMakers
组件的render()
方法实现了生成的视图,如下所示:
render() {
return <Switch>
<Route exact path='/winemakers' render={this.renderWineMakersList}/>
<Route path='/winemakers/WM1' render={() => (<WineMaker code='WM1' />}/>
<Route path='/winemakers/WM2' render={() => (<WineMaker code='WM2' />}/>
</Switch>;
}
这段代码很简单,也很有效,但它迫使我们在列表中添加新酿酒师时添加一条新路线。
我们可以通过使用path
参数来避免这种情况,如下代码所示:
render() {
return <Switch>
<Route exact path='/winemakers' render={this.renderWineMakersList}/>
<Route path='/winemakers/:code' component={WineMaker}/>
</Switch>;
}
如您所见,我们现在可以通过指定一个:code
参数来使用一条指向特定酿酒师的路线。路径表达式中的冒号表示 URL 的以下部分是一个变量值。您可能还注意到我们使用了component
属性而不是render
属性。事实上,在这种情况下,我们不需要显式地将酿酒师的代码传递给WineMaker
组件。React Router 通过在props
属性中提供一个特殊对象为我们实现了这一点。
让我们看一下组件的实现:
import React from 'react';
class WineMaker extends React.Component {
constructor() {
super();
this.wineMakers = [
{code: "WM1", name: "Wine & Wine", country: "Italy",
description:"Wine & Wine produces an excellent Italian wine..."},
export default WineMaker;
在组件的构造函数中,我们将酿酒师列表定义为一个对象数组。
在render()
方法中,我们通过比较数组中每个winemaker
对象的code
属性和this.props
提供的match.params.code
属性来寻找酿酒师显示。
We have implemented the winemakers
list as a property of the WineMaker
component, and not as a property of the state
object because since the list is embedded into the code and shouldn't change, we do not need to implement it as a state
property. Remember that we only identify data that changes over time as a state.
我们找到的对象用于适当地呈现关于WineMaker
的数据。
通常,通过路由到达的 React 组件接收this.props
属性中的match
对象。此对象包含有关Route
定义中匹配路径的信息。具体而言,match
对象的以下属性可用:
params
:属性与路径中参数匹配的对象;也就是说,前面有冒号的动态部分isExact
:这是一个布尔值,表示 URL 与路径匹配path
:分配给所选路由的path
属性的字符串url
:这是与路由路径匹配的 URL
通过执行以下步骤,我们可以看到最终结果。我们打开现有项目my-shop-05
,以显示前面代码的结果:
- 打开控制台窗口
- 移动到
my-shop-05
文件夹 - 运行
npm install
- 运行
npm start
活动:添加有关装运方法的视图
场景
我们想在 catalog 应用程序中添加一个部分,其中包含有关可用装运方法的信息。
瞄准
本活动的目的是探索 React 路由提供的组件。
完成步骤
- 考虑在先前活动中更改的项目(或者在 ProtoT0 席文件夹中存在的现有项目)。
- 根据通过
props
传递的代码(可用的运输方式包括经济交付(ECO))、标准交付(STD),创建一个ShippingMethods
组件,显示可用运输方式的列表,以及一个ShippingMethod
组件,显示每个运输方式的详细信息、快递(EXP)。 - 创建一个导航栏和一个路由配置,允许我们在
Catalog
和Shipping
方法视图中导航。
溶液
一种可能的解决方案是包含在Code/Chapter-3
的my-cart-04
文件夹中的解决方案。
总结
在本章中,我们学习了如何管理用户交互。我们特别介绍了以下内容:
- 不涉及组件状态更改的托管事件
- 已处理涉及组件状态更改的事件
- 探索了组件生命周期并学习了如何定制每个阶段
- 使用 React 路由的组件来配置组件之间的导航
本章是本书的结尾。它为理解 React 如何工作以及如何构建基于 React 的应用程序提供了基础知识。我们从介绍 React 开始,然后详细探讨了如何创建组件。最后,我们介绍了如何使用 React 管理用户交互。
版权属于:月萌API www.moonapi.com,转载请注明出处