React 类组件
在 React 16.8 之前,类组件是跟踪 React 组件状态和生命周期的唯一方法。函数组件被认为是“无状态”的。
随着 Hooks 的添加,函数组件现在几乎等同于类组件。它们的差异非常小,以至于您可能永远不需要在 React 中使用类组件。
尽管函数组件是首选,但目前没有计划从 React 中删除类组件。
本节将概述如何在 React 中使用类组件。
您可以跳过本节,改用函数组件。
React 组件
组件是独立且可复用的代码片段。它们与 JavaScript 函数的作用相同,但独立工作,并通过 render() 函数返回 HTML。
组件有两种类型,类组件和函数组件,本章将讲解类组件。
创建类组件
创建 React 组件时,组件名称必须以大写字母开头。
组件必须包含 extends React.Component
语句,此语句创建对 React.Component 的继承,并使您的组件可以访问 React.Component 的函数。
组件还需要一个 render()
方法,该方法返回 HTML。
示例
创建一个名为 Car
的类组件
class Car extends React.Component {
render() {
return <h2>Hi, I am a Car!</h2>;
}
}
现在您的 React 应用程序中有一个名为 Car 的组件,它返回一个 <h2>
元素。
要在应用程序中使用此组件,请使用与普通 HTML 相似的语法:<Car />
示例
在“根”元素中显示 Car
组件
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);
组件构造函数
如果您的组件中存在
函数,则在组件初始化时会调用此函数。constructor()
构造函数是您初始化组件属性的地方。
在 React 中,组件属性应保存在名为 state
的对象中。
您将在本教程的后面部分详细了解 state
。
构造函数也是您通过包含 super()
语句来尊重父组件继承的地方,该语句会执行父组件的构造函数,并且您的组件可以访问父组件的所有函数 (React.Component
)。
示例
在 Car 组件中创建一个构造函数,并添加一个 color 属性
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a Car!</h2>;
}
}
在 render() 函数中使用 color 属性
示例
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a {this.state.color} Car!</h2>;
}
}
属性
处理组件属性的另一种方法是使用 props
。
属性类似于函数参数,您可以将它们作为属性发送到组件中。
您将在下一章中详细了解 props
。
示例
使用属性将颜色传递到 Car 组件,并在 render() 函数中使用它
class Car extends React.Component {
render() {
return <h2>I am a {this.props.color} Car!</h2>;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car color="red"/>);
构造函数中的属性
如果您的组件具有构造函数,则应始终将属性传递给构造函数,以及通过 super()
方法传递给 React.Component。
示例
class Car extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h2>I am a {this.props.model}!</h2>;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car model="Mustang"/>);
组件中的组件
我们可以在其他组件中引用组件
示例
在 Garage 组件中使用 Car 组件
class Car extends React.Component {
render() {
return <h2>I am a Car!</h2>;
}
}
class Garage extends React.Component {
render() {
return (
<div>
<h1>Who lives in my Garage?</h1>
<Car />
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Garage />);
文件中的组件
React 的核心是代码重用,将一些组件插入单独的文件中可能很明智。
为此,请创建一个新的文件,使用 .js
文件扩展名,并将代码放在其中
请注意,文件必须以导入 React (与之前相同) 开头,并且必须以语句 export default Car;
结尾。
示例
这是新文件,我们将其命名为 Car.js
import React from 'react';
class Car extends React.Component {
render() {
return <h2>Hi, I am a Car!</h2>;
}
}
export default Car;
要使用 Car
组件,您必须在应用程序中导入该文件。
示例
现在我们在应用程序中导入 Car.js
文件,并且可以像在本地创建一样使用 Car
组件。
import React from 'react';
import ReactDOM from 'react-dom/client';
import Car from './Car.js';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);
React 类组件状态
React 类组件具有内置的 state
对象。
您可能已经注意到我们之前在组件构造函数部分使用了 state
。
The state
对象是您存储属于组件的属性值的地方。
当 state
对象发生更改时,组件会重新渲染。
创建 state 对象
state 对象在构造函数中初始化
示例
在构造函数方法中指定 state
对象
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {brand: "Ford"};
}
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
}
}
state 对象可以包含任意数量的属性
示例
指定组件所需的所有属性
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
}
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
}
}
使用 state
对象
通过使用 this.state.propertyname
语法,在组件中的任何位置引用 state
对象
示例
在 render()
方法中引用 state
对象
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
}
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
</div>
);
}
}
更改 state
对象
要更改 state 对象中的值,请使用 this.setState()
方法。
当 state
对象中的值发生更改时,组件将重新渲染,这意味着输出将根据新值进行更改。
示例
添加一个具有 onClick
事件的按钮,该事件将更改 color 属性
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
}
changeColor = () => {
this.setState({color: "blue"});
}
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
<button
type="button"
onClick={this.changeColor}
>Change color</button>
</div>
);
}
}
始终使用 setState()
方法更改 state 对象,它将确保组件知道它已更新,并调用 render() 方法 (以及所有其他生命周期方法)。
组件的生命周期
React 中的每个组件都有一个生命周期,您可以在其三个主要阶段对其进行监控和操作。
这三个阶段是:**挂载**、**更新** 和 **卸载**。
挂载
挂载是指将元素放入 DOM 中。
React 有四个内置方法,在挂载组件时按此顺序调用
constructor()
getDerivedStateFromProps()
render()
componentDidMount()
render()
方法是必需的,并且始终会被调用,其他方法是可选的,并且只有在您定义它们时才会被调用。
constructor
The constructor()
method is called before anything else, when the component is initiated, and it is the natural place to set up the initial state
and other initial values.
The constructor()
method is called with the props
, as arguments, and you should always start by calling the super(props)
before anything else, this will initiate the parent's constructor method and allows the component to inherit methods from its parent (React.Component
).
示例
The constructor
method is called, by React, every time you make a component
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
getDerivedStateFromProps
The getDerivedStateFromProps()
method is called right before rendering the element(s) in the DOM.
This is the natural place to set the state
object based on the initial props
.
It takes state
as an argument, and returns an object with changes to the state
.
下面的示例从最喜欢的颜色为“红色”开始,但 getDerivedStateFromProps()
方法根据 favcol
属性更新最喜欢的颜色
示例
The getDerivedStateFromProps
method is called right before the render method
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
static getDerivedStateFromProps(props, state) {
return {favoritecolor: props.favcol };
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header favcol="yellow"/>);
render
The render()
method is required, and is the method that actually outputs the HTML to the DOM.
示例
一个具有简单 render()
方法的简单组件
class Header extends React.Component {
render() {
return (
<h1>This is the content of the Header component</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
componentDidMount
The componentDidMount()
method is called after the component is rendered.
This is where you run statements that requires that the component is already placed in the DOM.
示例
最初我最喜欢的颜色是红色,但请稍等片刻,它将变为黄色
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
更新
生命周期中的下一个阶段是组件被更新。
当组件的 state
或 props
发生变化时,组件将被更新。
React 有五个内置方法,在组件更新时按此顺序调用
getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
render()
方法是必需的,并且始终会被调用,其他方法是可选的,并且只有在您定义它们时才会被调用。
getDerivedStateFromProps
此外,在更新时,还会调用 getDerivedStateFromProps
方法。这是组件更新时调用的第一个方法。
这仍然是根据初始 props 设置 state
对象的最佳位置。
下面的示例有一个按钮,可以将最喜欢的颜色更改为蓝色,但由于调用了 getDerivedStateFromProps()
方法,该方法使用 favcol 属性中的颜色更新 state,因此最喜欢的颜色仍然显示为黄色
示例
如果组件更新,则调用 getDerivedStateFromProps()
方法。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
static getDerivedStateFromProps(props, state) {
return {favoritecolor: props.favcol };
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header favcol="yellow" />);
shouldComponentUpdate
在 shouldComponentUpdate()
方法中,您可以返回一个布尔值,该值指定 React 是否应该继续渲染。
默认值为 true
。
以下示例显示了 shouldComponentUpdate()
方法返回 false
时会发生什么。
示例
阻止组件在任何更新时渲染。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
shouldComponentUpdate() {
return false;
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
示例
与上面示例相同,但这次 shouldComponentUpdate()
方法返回 true
。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
shouldComponentUpdate() {
return true;
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
render
当组件更新时,当然会调用 render()
方法,它必须将 HTML 重新渲染到 DOM 中,并包含新的更改。
以下示例有一个按钮,可以将喜欢的颜色更改为蓝色。
示例
单击按钮以更改组件的状态。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
getSnapshotBeforeUpdate
在 getSnapshotBeforeUpdate()
方法中,您可以访问更新前的 props
和 state
,这意味着即使在更新后,您也可以检查更新前的值。
如果存在 getSnapshotBeforeUpdate()
方法,您还应该包含 componentDidUpdate()
方法,否则您将收到错误。
以下示例可能看起来很复杂,但它所做的事情是:
当组件挂载时,它将使用喜欢的颜色“红色”渲染。
当组件已挂载时,计时器会更改状态,并且一秒钟后,喜欢的颜色将变为“黄色”。
此操作会触发更新阶段,由于此组件具有 getSnapshotBeforeUpdate()
方法,因此会执行此方法,并将消息写入空 DIV1 元素。
然后执行 componentDidUpdate()
方法,并将消息写入空 DIV2 元素。
示例
使用 getSnapshotBeforeUpdate()
方法找出更新前state
对象是什么样的。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
getSnapshotBeforeUpdate(prevProps, prevState) {
document.getElementById("div1").innerHTML =
"Before the update, the favorite was " + prevState.favoritecolor;
}
componentDidUpdate() {
document.getElementById("div2").innerHTML =
"The updated favorite is " + this.state.favoritecolor;
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<div id="div1"></div>
<div id="div2"></div>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
componentDidUpdate
在组件在 DOM 中更新后,会调用 componentDidUpdate
方法。
以下示例可能看起来很复杂,但它所做的事情是:
当组件挂载时,它将使用喜欢的颜色“红色”渲染。
当组件已挂载时,计时器会更改状态,并且颜色将变为“黄色”。
此操作会触发更新阶段,由于此组件具有 componentDidUpdate
方法,因此会执行此方法,并将消息写入空 DIV 元素。
示例
在 DOM 中渲染更新后,将调用 componentDidUpdate
方法。
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
componentDidUpdate() {
document.getElementById("mydiv").innerHTML =
"The updated favorite is " + this.state.favoritecolor;
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<div id="mydiv"></div>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
卸载
生命周期中的下一阶段是将组件从 DOM 中删除,或者用 React 的说法是卸载。
React 只有一个内置方法在卸载组件时被调用。
componentWillUnmount()
componentWillUnmount
当组件即将从 DOM 中删除时,会调用 componentWillUnmount
方法。
示例
单击按钮以删除标题。
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {show: true};
}
delHeader = () => {
this.setState({show: false});
}
render() {
let myheader;
if (this.state.show) {
myheader = <Child />;
};
return (
<div>
{myheader}
<button type="button" onClick={this.delHeader}>Delete Header</button>
</div>
);
}
}
class Child extends React.Component {
componentWillUnmount() {
alert("The component named Header is about to be unmounted.");
}
render() {
return (
<h1>Hello World!</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Container />);