React 类组件

在 React 16.8 之前,Class 类组件是跟踪 React 组件状态和生命周期的唯一方法。 函数组件被认为是"无状态的"。

加上 Hooks,Function 组件现在几乎等同于 Class 组件。 差异是如此之小,以至于您可能永远不需要在 React 中使用 Class 组件。

尽管 Function 组件是首选,但目前没有从 React 中删除 Class 组件的计划。

本节将概述如何在 React 中使用 Class 组件。

请随意跳过本节,改用函数组件。


React 组件

组件是独立且可重用的代码。 它们的用途与 JavaScript 函数相同,但独立工作并通过 render() 函数返回 HTML。

组件有两种类型,Class组件和Function组件,本章你将学习Class组件。


创建类组件

创建 React 组件时,组件名称必须以大写字母开头。

组件必须包含 extends React.Component 语句,该语句创建对 React.Component 的继承,并允许您的组件访问 React.Component 的功能。

组件还需要一个render()方法,该方法返回HTML。

实例

创建一个名为 Car

的 Class 组件
class Car extends React.Component {
  render() {
    return <h2>Hi, I am a Car!</h2>;
  }
}

现在你的 React 应用程序有一个名为 Car 的组件,它返回一个 <h2> 元素。

要在您的应用程序中使用此组件,请使用与普通 HTML 类似的语法: <Car />

实例

在"root"元素中显示 Car组件:

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);

运行实例 »


组件构造器

如果你的组件中有constructor()函数,该函数会在组件启动时调用。

构造函数是您启动组件属性的地方。

在 React 中,组件属性应该保存在一个名为 state 的对象中。

您将在本教程的后面部分了解有关 state 的更多信息。

构造函数也是您通过包含执行父组件的构造函数的 super() 语句和您的组件来尊重父组件的继承的地方 可以访问父组件的所有功能(React.Component)。

实例

在Car组件中创建构造函数,并添加颜色属性:

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 道具就像函数参数,你将它们作为属性发送到组件中。

您将在下一章了解更多关于 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"/>);

运行实例 »


构造函数中的道具

如果您的组件具有构造函数,则应该始终将 props 传递给构造函数,并通过 super() 方法传递给 React.Component。 p>

实例

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 Class 组件有一个内置的 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>
    );
  }
}

状态对象可以包含任意数量的属性:

实例

指定组件所需的所有属性:

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>
    );
  }
}

运行实例 »


改变状态对象

要更改状态对象中的值,请使用 this.setState() 方法。

state 对象中的值发生变化时,组件将重新渲染,即输出将根据新值发生变化。

实例:

添加一个带有 onClick 事件的按钮,该事件将更改颜色属性:

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() 方法来改变状态对象,它会确保组件知道它被更新并调用 render() 方法(以及所有 其他生命周期方法)。


组件的生命周期

React 中的每个组件都有一个生命周期,您可以在其三个主要阶段对其进行监控和操作。

三个阶段是:安装更新卸载


安装

安装意味着将元素放入 DOM。

React 有四个内置方法,在安装组件时按此顺序调用:

  1. constructor()
  2. getDerivedStateFromProps()
  3. render()
  4. componentDidMount()

render() 方法是必需的并且总是被调用,其他是可选的,如果你定义了它们就会被调用。


构造函数

constructor() 方法在其他任何事情之前被调用,当组件启动时,它是设置初始 状态等初始值。

constructor() 方法是用 props 作为参数调用的,你应该总是从 通过先调用 super(props),这将启动父级的构造方法并允许组件从其父级继承方法(React.Component).

实例:

每次创建组件时,React 都会调用 constructor 方法:

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

在渲染 DOM 中的元素之前调用 getDerivedStateFromProps() 方法。

这是根据初始 props 设置 state 对象的自然位置。

它接受 state 作为参数,并返回一个对 state 进行更改的对象。

下面的示例以最喜欢的颜色为"red"开始,但是 getDerivedStateFromProps() 方法根据 favcol 属性更新了最喜欢的颜色:

实例:

getDerivedStateFromProps 方法在渲染方法之前被调用:

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() 方法是必需的,并且是实际将 HTML 输出到 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

组件渲染后调用componentDidMount()方法。

这是您运行要求组件已放置在 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 />);

运行实例 »


更新中

生命周期的下一个阶段是组件更新

只要组件的 stateprops 发生变化,组件就会更新。

React 有五个内置方法,在组件更新时按此顺序调用:

  1. getDerivedStateFromProps()
  2. shouldComponentUpdate()
  3. render()
  4. getSnapshotBeforeUpdate()
  5. componentDidUpdate()

render() 方法是必需的并且总是被调用,其他是可选的,如果你定义了它们就会被调用。


getDerivedStateFromProps

同样在 updates 中调用 getDerivedStateFromProps 方法。 这是组件更新时调用的第一个方法。

这仍然是根据初始 props 设置 state 对象的自然位置。

下面的示例有一个按钮可以将最喜欢的颜色更改为蓝色,但是由于调用了 getDerivedStateFromProps() 方法,该方法使用来自 favcol 属性,最喜欢的颜色仍然呈现为黄色:

实例:

如果组件更新,则调用 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() 方法当然会在组件得到updated更新时调用,它必须将 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() 方法中,您可以访问 propsstate before 更新,这意味着即使在更新之后,您也可以检查更新之前before之前的值。

如果存在 getSnapshotBeforeUpdate() 方法,您还应该包含 componentDidUpdate() 方法, 否则会报错。

下面的例子可能看起来很复杂,但它所做的只是:

当组件安装时,它会以最喜欢的颜色"red"呈现。

当组件被挂载后,一个定时器改变状态,一秒后,最喜欢的颜色变成"yellow"。

这个动作触发了update阶段,由于这个组件有一个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

componentDidUpdate 方法在组件在 DOM 中更新后调用。

下面的例子可能看起来很复杂,但它所做的只是:

当组件安装时,它会以最喜欢的颜色"red"呈现。

当组件被挂载后,一个计时器改变状态,颜色变成"yellow"。

这个动作触发了update阶段,由于这个组件有一个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 中删除组件,或者 unmounting 卸载, React 喜欢这样称呼它。

React 只有一个内置方法,在卸载组件时会被调用:

  • componentWillUnmount()

componentWillUnmount

componentWillUnmount 方法在组件即将从 DOM 中移除时调用。

实例:

点击按钮删除表头:

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 />);

运行实例 »