在本章中,我们将学习如何实现 React 组件,如何将多个组件组装成一个组件,以及如何管理它们的内部状态。我们将通过构建一个简单的应用程序来探索 React 组件的实现。该应用程序将逐步实施,以便将概述的概念付诸实践。
在本章结束时,您将能够:
- 创建基本组件
- 使用 JSX 定义组件的标记
- 组合多个 React 组件以创建复杂的 UI 元素
- 管理组件的内部状态
如前一章所定义,组件是 React 的基本构建块。实际上,用户界面中的任何可视项都可以是组件。从形式上看,我们可以说 React 组件是定义用户界面一部分的 JavaScript 代码。
在文件中考虑下面的代码:
import React from 'react';
class Catalog extends React.Component {
render() {
return <div><h2>Catalog</h2></div>;
}
}
export default Catalog;
这是一个 ECMAScript 2015 模块,定义了一个基本的 React 组件。
它从react
模块导入React
名称空间,并通过扩展React.Component
类定义Catalog
类。模块将Catalog
类导出为默认导出。
这个定义中有趣的部分是render()
方法的实现。
render()
方法定义组件的可视部分。它可以执行任何 JavaScript 代码,并且应该返回一个定义其可视输出的标记表达式。React 组件必须存在render()
方法。在我们的示例中,render()
方法返回以下标记:
<div><h2>Catalog</h2></div>
它看起来像 HTML;虽然它使用类似的语法,但它定义了称为元素的普通对象。React 元素类似于文档对象模型(DOM元素),但更轻、更高效。因此,React 组件生成一组 React 元素,这些元素将由库引擎映射到 DOM 元素。这组 React 元素称为虚拟 DOM,是浏览器 DOM 的轻量级表示。React 只在严格必要时才负责更新 DOM 以匹配虚拟 DOM。这种方法允许 React 在呈现用户界面时具有非常高的性能。
render()
方法必须符合几个约束条件:
- 它是强制性的;也就是说,每个 React 组件都必须实现它
- 它必须返回一个 React 元素;即,包含任何嵌套元素的单个标记项
- 它应该是一个纯函数;也就是说,它不应更改组件的内部状态(我们将在下一节中进一步详细讨论此主题)
- 它不应该直接与浏览器交互;也就是说,它不应该包含试图访问 DOM 的语句
A pure function is a function whose output result depends only on its input data, and its execution has no side effect, like, for example, updating a global variable. Given an input value, a pure function always returns the same result.
A pure component is a component that acts like a pure function. This means that, given the same initial conditions, it always renders the same output.
It is very important to keep the render()
method a pure function. This avoids weird bugs, as we will see in the next chapter.
一旦我们定义了我们的组件,我们就可以将它用作任何其他 React 组件中的 React 元素。例如,我们知道 React 应用程序本身已经是一个 React 组件。让我们回忆一下App.js
文件中create-react-app
工具生成的代码:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}
export default App;
我们可以看到,该代码与我们定义的Catalog
组件具有相同的结构。为了在App
组件中使用我们的组件,让我们更改此代码:
import React, { Component } from 'react';
import './App.css';
import Catalog from './Catalog';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">The Catalog App</h1>
</header>
<Catalog />
</div>
);
}
}
export default App;
我们通过删除一些自动生成的标记来简化代码,然后导入Catalog
组件,并将<Catalog />
元素放在应用程序的render()
方法返回的<div>
元素中。
以下步骤打开现有项目my-shop-01
,以显示先前代码更改的结果:
- 打开控制台窗口
- 移动到
my-shop-1
文件夹 - 运行
npm install
- 运行
npm start
下面是我们将在浏览器窗口中看到的示例:
我们已经构建了我们的第一个 React 组件,我们可以看到它在运行!
也许您已经注意到,我们在App
组件模块中有一个关于 CSS 文件的import
语句:
import React, { Component } from 'react';
import './App.css';
import Catalog from './Catalog';
这似乎有点奇怪,因为import
语句应该只适用于 JavaScript 代码。但是,由于create-react-app
提供的开发环境,我们可以使用相同的语法,即使是 CSS 文件。这允许我们在我们的组件中使用App.css
中定义的类和其他 CSS 定义,保持组件特定的样式接近组件定义本身。例如,如果我们希望我们的Catalog
组件的标题为红色,我们可以按照下面所示进行操作。
我们现在将更改现有项目my-shop-01
的内容,以便添加一些 CSS 代码并以红色显示目录标题:
- 打开控制台窗口。
- 移动到
my-shop-1/src
文件夹。 - 创建一个文件
Catalog.css
,并添加以下代码:
h2 { color: red }
- 打开
Catalog.js
文件,添加语句导入Catalog.css
模块,如下图:
import React from 'react';
import './Catalog.css';
class Catalog extends React.Component {
render() {
return <div><h2>Catalog</h2></div>;
}
}
export default Catalog;
- 运行
npm start
并查看结果。
You can find a project ready in the my-shop-02
folder at Code/Chapter-2
.
浏览器将以红色显示目录标题:
The CSS import is not a React feature, and it is not required by React. It is a convenience provided by the development environment, built by create-react-app
. In particular, this feature is provided by webpack, one of the most frequently used bundlers and module loaders.
You should take this aspect into account when you want to migrate the application into a development environment not based on webpack.
场景
我们的电子商店需要一辆购物车。
瞄准
此活动的目的是开始使用 React 定义组件。
完成步骤
- 我们应该定义一个 React 组件,作为购物车的基础
- 它应该是一个只显示字符串
Cart
的组件
Create a new React application by using create-react-app
, and change the application, as shown in the current section.
溶液
一种可能的解决方案是包含在Code/Chapter-2/
的my-cart-01
文件夹中的解决方案。
在前面的示例中,我们使用类似 HTML 的标记表达式定义了组件的render()
方法返回的可视输出。例如,让我们看看Catalog
组件的定义:
import React from 'react';
import './Catalog.css';
class Catalog extends React.Component {
render() {
return <div><h2>Catalog</h2></div>;
}
}
export default Catalog;
标记表达式未使用 JavaScript 语法,但包含在 JavaScript 代码段中。为什么我们混合使用 HTML 和 JavaScript 语法?这怎么可能?
让我们首先说,描述 React 组件的可视化输出的类似 HTML 的语言称为JSX。该语言使用 XML 表达式扩展 JavaScript,以简化 JavaScript 代码中 HTML 元素的创建。你可能会认为它是一种document.write("...")
,但更强大。事实上,在构建 React 应用程序时,JSX 标记由特定的解析器进行预处理,以生成纯 JavaScript 代码。因此,我们可以利用使用声明性标记语言的简单性,该语言将自动转换为优化的 JavaScript 代码。
如前所述,JSX 表达式创建 React 元素,它是 HTML 元素的对应项。从语法的角度来看,JSX 表达式是包含任何嵌套元素的单个标记项。因此,以下是一个有效的 JSX 表达式:
<div><h2>Catalog</h2></div>
以下是无效的 JSX 表达式,因为它包含两个标记项:
<div><h2>Catalog</h2></div>
<div><img src="image.png" /></div>
JSX expressions are XML fragments, so they are compliant with XML syntax rules. This means that, among other things, the markup is case-sensitive, and all of the tags must be closed.
For example, the following JSX expression is not valid:
<img src="image.png">
Its valid version is the following:
<img src="image.png"/>
我们可以将 JSX 表达式分配给变量,如下例所示:
import React from 'react';
import './Catalog.css';
class Catalog extends React.Component {
render() {
let output = <div><h2>Catalog</h2></div>;
return output;
}
}
export default Catalog;
我们还可以通过将任何 JavaScript 表达式用大括号括起来,将其嵌入 JSX 表达式中,如下例所示:
import React from 'react';
import './Catalog.css';
class Catalog extends React.Component {
render() {
let title = "Catalog";
return <div><h2>{title}</h2></div>;
}
}
export default Catalog;
当然,JavaScript 表达式可以是我们所需要的那样复杂,如以下组件定义中所示:
import React from 'react';
import './Catalog.css';
class Catalog extends React.Component {
render() {
let title = "The Catalog of today " + new Date().toDateString();
return <div><h2>{title}</h2></div>;
}
}
export default Catalog;
In addition to optimizing output rendering, JSX also provides support to prevent injection attacks. In fact, any value embedded in a JSX expression escapes before being rendered. This, for example, prevents malicious code from being inserted by a user's input.
JavaScript 和 JSX 表达式组合的一种常见用法称为条件呈现;也就是说,这是一种允许您基于某些布尔条件生成 JSX 表达式的技术。考虑下面的例子:
import React from 'react';
import './Message.css';
class Message extends React.Component {
render() {
let message;
let today = new Date().getDay();
if (today == 0) {
message = <div className="sorry">We are closed on Sunday...</div>;
} else {
message = <div className="happy">How can we help you?</div>
}
return message;
}
}
export default Message;
在前面的示例中,render()
方法根据一周中的当前日期返回一条或另一条消息。这导致使用不同的消息和 CSS 类生成 React 元素,但我们甚至可以返回完全不同的标记。
可以将 JSX 表达式放在多行中,如下所示:
import React from 'react';
import './Catalog.css';
class Catalog extends React.Component {
render() {
let title = "Catalog";
return <div>
<h2>{title}</h2>
</div>;
}
}
export default Catalog;
It is very important when returning a JSX expression to start it in the same line of the return
statement, as in the previous example. If you want to start the JSX expression on a new line, you need to enclose it in round brackets and put the left bracket on the same line as the return
statement, as in the following example:
return (
<div>
<h2>Catalog</h2>
</div>);
您可以使用用花括号括起来的 JavaScript 语法将注释放在 JSX 表达式中。以下是带注释的 JSX 表达式示例:
<div>
<h2>Catalog</h2>
{//This is a comment}
{/* This is a comment, too */}
</div>;
JSX 标记与 HTML 标记匹配,这就是为什么我们可以使用整个 HTML 语法来定义 JSX 元素。但是,有一些限制:
- 所有 HTML 标记都是小写的
- 您需要使用
className
而不是class
属性 - 您需要使用
htmlFor
而不是for
属性
下面的示例显示如何使用className
属性而不是class
:
<div className="catalog-style">
<h2>Catalog</h2>
</div>;
JSX uses the className
and htmlFor
attributes instead of class
and for
because as JSX expressions are inside JavaScript, class
and for
could clash with the corresponding reserved keywords.
场景
图形部门为您提供了一个 HTML 代码段,您需要将其转换为 JSX 以创建 React 组件。
瞄准
本活动的目的是了解 HTML 和 JSX 之间的区别。
完成步骤
- 打开
Code02.txt
文件 - 将它包含的 HTML 代码转换为 JSX
溶液
一种可能的解决方案是包含在Code/Chapter-2/
的activity-b.html
文件中的解决方案。
在定义 React 组件时,我们可以通过将该组件用作 React 元素,将其用作另一个组件的子组件。当我们将Catalog
成分包含在App
成分中时,我们已经看到了这一点,但让我们进一步分析这个成分。
现在,我们将了解如何组合组件以创建新的复杂组件:
- 打开
my-shop-03
文件夹中的src/ProductList.js
文件 - 跟随课文直到本节结束
让我们考虑下面的组成部分:
import React from 'react';
class ProductList extends React.Component {
render() {
return <ul>
<li>
<h3>Traditional Merlot</h3>
<p>A bottle of middle weight wine, lower in tannins (smoother),
with a more red-fruited flavor profile.</p>
</li>
<li>
<h3>Classic Chianti</h3>
<p>A medium-bodied wine characterized by a marvelous freshness with
a lingering, fruity finish</p>
</li>
<li>
<h3>Chardonnay</h3>
<p>A dry full-bodied white wine with spicy, bourbon-y notes in an
elegant bottle</p>
</li>
<li>
<h3>Brunello di Montalcino</h3>
<p>A bottle red wine with exceptionally bold fruit flavors,
high tannin, and high acidity</p>
</li>
</ul>;
}
}
export default ProductList;
此组件定义葡萄酒、名称和描述的列表。
我们想将我们的Catalog
组件与葡萄酒列表整合。既然我们已经创建了ProductList
组件,我们就可以在Catalog
组件的 JSX 标记中将其用作标记,如下所示:
import React from 'react';
import ProductList from './ProductList';
class Catalog extends React.Component {
render() {
return <div>
<h2>Catalog</h2>
<ProductList />
</div>;
}
}
export default Catalog;
如您所见,我们只是简单地导入了ProductList
组件,以便在Catalog
组件的模块中使用它,并且我们使用了ProductList
标记来显示酒单。
运行npm start
启动应用程序。生成的页面将如下所示:
We said that the HTML tags in JSX expressions should always be in lowercase. However, we used the ProductList
tag in Pascal case.
与组件对应的标记必须遵循类定义中使用的大小写,按照惯例,组件类名称使用 Pascal 大小写,即使 React 不需要它。
按照上一章提供的指导原则,React 组件的易组合性使得创建用户界面变得非常简单。我们可以将页面布局分解为一组分层的组件,每个组件都由其他组件组成。这种方法允许我们关注单个组件的行为,并提高其可重用性。
场景
我们想为我们的购物车创建一些内容。
瞄准
本活动的目的是合成反应组分。
完成步骤
集成先前创建的Cart
组件,以包含一个CartList
组件,显示两项。
溶液
一种可能的解决方案是包含在Code/Chapter-2/
的my-cart-02
文件夹中的解决方案。
我们在上一节中定义的组件是不实用的。让我们再看一遍:
import React from 'react';
import './ProductList.css';
class ProductList extends React.Component {
render() {
return <ul>
<li>
<h3>Traditional Merlot</h3>
<p>A bottle of middle weight wine, lower in tannins (smoother),
with a more red-fruited flavor profile.</p>
</li>
<li>
<h3>Classic Chianti</h3>
<p>A medium-bodied wine characterized by a marvelous freshness with
a lingering, fruity finish</p>
</li>
<li>
<h3>Chardonnay</h3>
<p>A dry full-bodied white wine with spicy, bourbon-y notes in an
elegant bottle</p>
</li>
<li>
<h3>Brunello di Montalcino</h3>
<p>A bottle of red wine with exceptionally bold fruit flavors, high
tannin, and high acidity</p>
</li>
</ul>;
}
}
export default ProductList;
列表项都定义为 JSX 标记,因此如果需要更改目录产品的图形外观,则需要更改每个<li>
元素的所有引用。
通过进一步分解用户界面,我们可以实现更好的实现。我们可以将每个列表项看作一个组件,并且将其作为下面代码定义的一个组件:
import React from 'react';
class Product extends React.Component {
render() {
return <li>
<h3>Product name</h3>
<p>Product description</p>
</li>;
}
}
export default Product;
此代码充当每个列表项的模板,以便我们可以动态构建产品列表,如下所示:
import React from 'react';
import './ProductList.css';
import Product from './Product';
class ProductList extends React.Component {
render() {
let products = [
{code:"P01", name: "Traditional Merlot", description: "A bottle
of middle weight wine, lower in tannins (smoother), with a
more red-fruited flavor profile."},
{code:"P02", name: "Classic Chianti", description: "A medium-bodied
wine characterized by a marvelous freshness with a lingering,
fruity finish"},
{code:"P03", name: "Chardonnay", description: "A dry full-bodied
white wine with spicy, bourbon-y notes in an elegant bottle"},
{code:"P04", name: "Brunello di Montalcino", description: "A bottle
of red wine with exceptionally bold fruit flavors, high tannin,
and high acidity"}
];
let productComponents = [];
for (let product of products) {
productComponents.push(<Product/>);
}
return <ul>{productComponents}</ul>;
}
}
export default ProductList;
我们可以看到对象数组的定义,products
,其中包含每个产品的相关数据。第二个数组productComponents
将包含通过将产品数据与Product
组件的标记合并而创建的 React 组件列表。for
循环用于执行这种合并。最后,将返回由<ul>
元素包围的结果productComponents
数组。
即使代码结构看起来是正确的,结果也不会如预期的那样。事实上,我们将获得一个带有固定名称和描述的项目列表,我们将其放入Product
组件定义中。换句话说,数据和组件定义之间的合并没有发生。
实际上,我们需要一种方法将每个产品的数据传递给Component
类。让我们把 React 组件看作是普通的 JavaScript 函数。它们可以实现为返回 React 元素的函数,并且,与任何函数一样,组件可以具有数据输入。此类数据输入通过 JSX 属性传递,并可通过名为**props**
的特殊对象在组件内部访问。让我们更改ProductList
组件的代码,以便通过 JSX 属性传递数据:
import React from 'react';
import Product from './Product';
class ProductList extends React.Component {
render() {
let products = [
{code:"P01", name: "Traditional Merlot", description: "A bottle
of middle weight wine, lower in tannins (smoother), with a
more red-fruited flavor profile."},
{code:"P02", name: "Classic Chianti", description: "A medium-bodied
wine characterized by a marvelous freshness with a lingering,
fruity finish"},
{code:"P03", name: "Chardonnay", description: "A dry full-bodied
white wine with spicy, bourbon-y notes in an elegant bottle"},
{code:"P04", name: "Brunello di Montalcino", description: "A bottle
of red wine with exceptionally bold fruit flavors, high tannin,
and high acidity"}
];
let productComponents = [];
for (let product of products) {
productComponents.push(<Product
item={product}/>);
}
return <ul>{productComponents}</ul>;
}
}
export default ProductList;
我们在<Product>
标记中添加了一个item
属性,并将products
数组中的一个对象分配给它。这允许我们将每个产品的数据传递给Product
组件。
另一方面,为了接收和管理传递的数据,我们修改了Product
组件的代码:
import React from 'react';
class Product extends React.Component {
render() {
return <li>
<h3>{this.props.item.name}</h3>
<p>{this.props.item.description}</p>
</li>;
}
}
export default Product;
You can find a project ready in the my-shop-04
folder at Code/Chapter-2/
.
每个反应组分都有一个props
属性。此属性的目的是收集传递给组件本身的数据输入。只要将 JSX 属性附加到 React 元素,具有相同名称的属性就会附加到props
对象。因此,我们可以使用附加属性访问传递的数据。在我们的示例中,我们发现通过映射到this.props.item
属性的item
属性传递的产品数据。
props
are immutable; that is, they are read-only properties.
这个新的实现允许像以前一样显示目录,但使图形标记独立于产品的数据。
在组件层次结构中,数据传播非常重要。它允许我们将组件视为具有输入和输出的函数。此外,props
的不变性允许我们将组件视为纯函数,这些函数没有副作用(因为它们不会更改输入数据)。我们可以将从一个组件传递到另一个组件的数据视为单向数据****流,从父组件流向子组件。这给了我们一个更可控的系统。
下图显示了我们如何想象组件层次结构中的数据传播,理想情况下:
状态的更改会导致通过props
属性向子组件传播数据。
场景
我们希望使CartList
组件成为一个动态组件,以便它能够根据接收到的数据调整其内容。
瞄准
此活动的目的是组成 React 组件并在它们之间传递数据。
完成步骤
- 创建一个显示项目名称的
CartItem
组件。 - 更改先前创建的
CartList
组件,使其基于items
数组由CartItem
实例动态组成。
溶液
一种可能的解决方案是包含在Code/Chapter-2
的my-cart-03
文件夹中的解决方案。
组件能够存储随时间变化的数据。
当组件显示可以随时间变化的数据时,我们希望尽快显示变化。例如,考虑 AutoT0:Up 组件:它显示了包含在 Type T1 数组中的产品列表。如果将新产品添加到阵列中,我们希望立即显示它。React 提供了一种机制,支持在数据更改时自动呈现组件。这种机制基于状态的概念。
React state
is a property that represents data that changes over time. Every component supports the state
property, but it should be used carefully.
再考虑一下,Ty0T0.组件:
import React from 'react';
import Product from './Product';
class ProductList extends React.Component {
render() {
let products = [
{code:"P01", name: "Traditional Merlot", description: "A bottle
of middle weight wine, lower in tannins (smoother), with a more
red-fruited flavor profile."},
{code:"P02", name: "Classic Chianti", description: "A medium-bodied
wine characterized by a marvelous freshness with a lingering,
fruity finish"},
{code:"P03", name: "Chardonnay", description: "A dry full-bodied
white wine with spicy, bourbon-y notes in an elegant bottle"},
{code:"P04", name: "Brunello di Montalcino", description: "A bottle
of red wine with exceptionally bold fruit flavors, high tannin,
and high acidity"}
];
let productComponents = [];
for (let product of products) {
productComponents.push(<Product item={product}/>);
}
return <ul>{productComponents}</ul>;
}
}
export default ProductList;
从实际的角度来看,它没有那么有用。它显示产品的硬编码列表。如果我们想添加新产品,我们需要对组件源代码进行更改。
在真实场景中,我们希望使组件的代码独立于产品数据。例如,我们可以通过向 web 服务器发出 HTTP 请求来获取产品数据。在这种情况下,products
数组将表示随时间变化的数据:最初是一个空数组,然后用从服务器接收到的产品数据填充该数组,随后向服务器发出的请求将再次对其进行更改。
存储随时间变化的数据的组件称为有状态组件。有状态组件将状态存储在this.state
属性中。要通知组件状态已更改,必须使用setState()
方法。此方法为组件设置新状态;它不会更新它。状态的更改触发组件的渲染;也就是说,render()
方法的自动执行。
让我们看看如何通过更改ProductList
组件定义来管理状态:
import React from 'react';
import Product from './Product';
class ProductList 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));
}
render() {
let productComponents = [];
for (let product of this.state.products) {
productComponents.push(<Product item={product}/>);
}
return <ul>{productComponents}</ul>;
}
}
export default ProductList;
我们将构造函数添加到组件中。构造函数运行超类构造函数,并将组件的初始状态设置为具有空数组的products
属性的对象。
然后,通过fetch()
向服务器发送 GET HTTP 请求。由于请求是异步的,因此组件的初始呈现将是产品的空列表。
State initialization is the only case where you can assign a value to the this.state
property without using setState()
.
当收到 HTTP 响应时,用setState()
改变组件的状态。此状态更改导致自动执行render()
,将显示从服务器接收的产品列表。
现在我们知道了如何管理组件的状态,在使用setState()
方法时需要记住以下几点:
setState()
将新数据与状态中已包含的旧数据合并,并覆盖以前的状态setState()
触发render()
方法的执行,所以千万不要显式调用render()
组件状态管理似乎非常简单。然而,在决定什么应该被视为状态以及哪个组件应该是有状态的时,很容易遇到麻烦。
以下是关于州政府的一些建议:
- 状态应包含表示 UI 中随时间变化的数据所需的最小数据;从这个最小数据中得到的任何信息都应该在
render()
方法中进行计算 - 应尽可能避免状态,因为它会增加组件的复杂性
- 有状态组件应位于 UI 的组件层次结构的较高位置
我们可以考虑最后一条建议,这是第二条建议的结果。如果我们应该限制状态的使用,我们应该减少有状态组件的数量。因此,将有状态组件的角色分配给作为用户界面中组件层次结构根的组件是一个很好的规则。您还记得我们在上一章中讨论的组件分类为表示组件和容器组件吗?通常,容器组件是有状态组件的良好候选对象。
在我们的示例应用程序中,我们将有状态组件的角色分配给ProductList
组件。即使它是一个容器组件,它也不是应用程序的组件层次结构中最高的。也许这个角色更适合Catalog
组件。在这种情况下,我们应该将获取数据的逻辑移到Catalog
组件内部,如下代码所示:
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));
}
render() {
return <div><h2>Wine Catalog</h2><ProductList
items={this.state.products}/></div>;
}
}
export default Catalog;
You can find a project ready in the my-shop-05
folder at Code/Chapter-2
.
场景
为了使Cart
组件生产就绪,我们添加了状态管理和动态数据加载。
瞄准
本活动的目的是熟悉组件状态管理。
完成步骤
将先前创建的Cart
组件更改为添加状态管理,以便通过 HTTP 请求加载数据,并自动更新购物车的内容。
溶液
一种可能的解决方案是包含在Code/Chapter-2/
的my-cart-04
文件夹中的解决方案。
在本章中,我们开始创建 React 组件并探索其基本特性。特别是,我们:
- 学习了如何将组件定义为从
React.Component
派生的类,以及如何导入特定的 CSS 样式 - 探索了 JSX 的语法,它允许我们快速定义组件的图形方面,并使用在别处定义的 React 组件
- 组合反应组件以构建其他组件
- 使用状态管理功能,以便 React 组件在数据更改时自动更新其可视化表示
在下一章中,我们将分析如何使用基于 React 的应用程序管理用户交互;换句话说,就是如何捕获事件并使 UI 对这些事件做出反应。