React 类组件


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

添加了 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"root" 元素中的组件:

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() 函数中使用颜色属性:

示例

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

如果你的组件有构造函数,则 props 应始终传递给构造函数,并通过以下方式传递给 React.Component:super()方法。

示例

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前面的组件构造函数部分。

这个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对象

请参阅state通过使用组件中任何位置的对象this.state.propertyname语法:

例子:

请参阅state对象在render()方法:

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对象

要更改状态对象中的值,请使用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()当组件启动时,方法会在其他任何事情之前被调用,并且它是设置初始组件的自然位置state和其他初始值。

这个constructor()方法被调用props,作为参数,并且您应该始终从调用super(props)首先,这将启动父级的构造函数方法并允许组件从其父级继承方法(React.Component)。

例子:

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

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

运行示例 »


从Props获取DerivedState

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

这是设置的自然位置state基于初始对象props

它需要 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()method 是必需的,并且是实际将 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()组件渲染后调用该方法。

您可以在此处运行要求组件已放置在 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 有五个内置方法,当组件更新时,这些方法将按以下顺序调用:

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

这个render()方法是必需的并且将始终被调用,其他方法是可选的并且如果您定义它们就会被调用。


从Props获取DerivedState

也在更新这个getDerivedStateFromProps方法被调用。这是组件更新时调用的第一个方法。

这仍然是设置state基于初始 props 的对象。

下面的示例有一个按钮,可以将最喜欢的颜色更改为蓝色,但是由于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()方法中你可以返回一个布尔值来指定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()当组件获取时当然会调用方法更新,它必须使用新的更改将 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()您可以访问的方法propsstate更新,这意味着即使在更新之后,您也可以检查值是什么更新。

如果getSnapshotBeforeUpdate()方法已经存在,您还应该包括 componentDidUpdate()方法,否则会出错。

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

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

当组件已安装,计时器改变状态,一秒钟后,最喜欢的颜色变成"yellow"。

此操作会触发更新阶段,并且由于该组件具有 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 中更新后调用该方法。

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

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

当组件已安装,计时器改变状态,颜色变为"yellow"。

此操作会触发更新阶段,并且由于该组件具有componentDidUpdate方法,执行该方法并在空 DIV 元素中写入一条消息:

例子:

这个componentDidUpdate更新在 DOM 中渲染后调用方法:

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 中删除时调用该方法。

例子:

单击按钮删除标题:

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

运行示例 »