React.Component — 类组件及其工作原理

作者: IT Sectr 发布日期: 2026-07-04 阅读时间: 9 分钟

React.Component — 在 React 中使用继承创建组件的基础类。在 16.8 版本中引入 hooks 之前,类组件是管理状态和生命周期的唯一方式。根据 React, 2024,类组件仍然受支持,尽管带有 hooks 的函数式组件被推荐用于新项目。

要点

  • React.Component — 类组件通过 extends Component 继承的基础类。
  • 状态通过 this.state 管理,仅通过 this.setState 更新 — 禁止直接修改。
  • 生命周期包括 componentDidMount、componentDidUpdate 和 componentWillUnmount 方法。
  • this 在类方法中需要绑定上下文 — 通过 bind、箭头函数或 class fields。
  • 迁移到函数式组件可以逐步进行:hooks 和类可以在同一个项目中共存。

什么是 React.Component?

React.Component — 一个抽象类,提供用于处理状态、props 和组件生命周期的内置方法。要创建类组件,您需要定义一个继承自 React.Component 的类,并实现 render 方法。

React.Component 出现在 React 的第一个版本(2013 年)中,并在五年内一直是创建组件的主要方式。React 生态系统围绕类构建:高阶组件(HOC)、render props、上下文 — 所有这些模式都是通过类语法实现的。

随着 2019 年 React 16.8 的发布,React 团队引入了 hooks 作为类的替代方案。hooks 解决了相同的任务 — 状态、副作用、上下文 — 但没有继承和复杂的上下文绑定。React.Component 仍然完全受支持,但对于新项目,推荐使用函数式方法。

创建类组件

最简类组件 — 只有一个 render 方法并返回 React 元素的类。render — 唯一必需的方法。它必须是 this.props 和 this.state 的纯函数:相同的 props 和状态集产生相同的结果。

js
import React, { Component } from 'react';

class Welcome extends Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

构造函数和状态初始化

构造函数在挂载之前执行。在其中调用 super(props) 以将 props 传递给父类,并初始化 this.state。不建议将构造函数用于其他目的 — 订阅、API 调用:为此有 componentDidMount。

js
class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    return <p>Count: {this.state.count}</p>;
  }
}

通过 this.state 和 this.setState 管理状态

this.state — 包含组件数据的对象。直接修改它(this.state.count = 1)是不允许的 — 不会触发重新渲染并破坏可预测性。必须通过 this.setState 更新状态,它会创建一个新的状态对象并触发重新渲染。

setState 可以接受对象或函数。当新状态依赖于先前状态时,函数形式更可取:this.setState(prev => ({ count: prev.count + 1 }))。React 可以将多个 setState 调用分组到一个批次中以优化性能。

js
class Toggle extends Component {
  constructor(props) {
    super(props);
    this.state = { isOn: false };
  }

  handleClick() {
    this.setState(prev => ({ isOn: !prev.isOn }));
  }

  render() {
    return (
      <button onClick={() => this.handleClick()}>
        {this.state.isOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

setState 的一个重要特性 — 它是异步的。调用 setState 后,状态不会立即更新。如果需要在更新后执行操作,请将回调作为第二个参数传递:this.setState(newState, () => console.log(this.state))

生命周期方法

类组件具有预定义的方法,React 在特定时刻调用这些方法。挂载 — constructor → render → componentDidMount。更新 — render → componentDidUpdate。卸载 — componentWillUnmount。

方法阶段用途
constructor挂载初始化状态和绑定方法
render每次返回 React 元素(必需)
componentDidMount挂载后API 请求、订阅、定时器
componentDidUpdate更新后响应 props/状态的变化
componentWillUnmount删除前清理订阅、定时器、取消事件订阅

ComponentDidMount — 数据请求

componentDidMount — 首次渲染后副作用的主要位置。在这里执行 HTTP 请求、建立 WebSocket 连接和启动定时器。如果您不在 componentWillUnmount 中清理订阅,将发生内存泄漏。

js
class UserProfile extends Component {
  componentDidMount() {
    fetch(`/api/users/${this.props.userId}`)
      .then(res => res.json())
      .then(data => this.setState({ user: data }));
  }

  componentWillUnmount() {
    // 卸载时取消请求
  }

  render() {
    return <div>{this.state.user?.name}</div>;
  }
}

方法中 this 上下文的绑定

在 JavaScript 中,类方法默认不绑定到实例。如果您将方法作为回调传递 — 给事件处理程序、定时器 — this 将是 undefined(严格模式)或 window(非严格模式)。没有绑定,this.setState 会抛出错误。

有三种绑定方式:在构造函数中使用 bind、在回调中使用箭头函数和带有箭头函数的 class field。第一种方式是 React 的官方推荐:在构造函数中 bind 一次,无需在每次渲染时重新创建函数。

js
// 方法 1:在构造函数中使用 bind(推荐)
class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({ clicked: true });
  }

  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

Class field — 具有自动绑定的现代语法。类属性中的箭头函数从构造函数的作用域中捕获 this。缺点 — 方法在每个实例上创建,而不是在原型上,这会增加同类数百个组件的内存消耗。

类组件与函数式组件的比较

在类和函数之间的选择 — 不仅仅是语法问题。带有 hooks 的函数式组件解决了类固有的问题:在不同生命周期方法中(componentDidMount + componentDidUpdate)逻辑重复、this 的复杂性以及无法将相关逻辑提取到可重用块中。

函数式组件更易于测试 — 它们没有内部状态(hooks 之前只在类中有)并且不需要挂载到 DOM 来检查回调。React 建议所有新项目使用函数式组件,文档和示例都是用它们编写的。

类组件在处理遗留代码时仍然是最佳选择。如果项目在 2019 年之前启动,它可能包含成千上万个类组件。在一个 sprint 中将它们全部重写为 hooks 是有风险的。React 保证向后兼容性:类组件不会被移除。

从类到 hooks 的迁移策略

逐步迁移从分析组件开始。无状态的简单组件(stateless)首先被转换 — 它们很容易被函数替代。然后 — 具有一到两个状态字段的组件,其中 useState 直接替换 this.state 和 this.setState。

具有多个生命周期方法的复杂组件通过 useEffect 进行转换。来自 componentDidMount + componentDidUpdate 的逻辑被拆分为具有不同依赖关系的单独 useEffect。componentWillUnmount 被 useEffect 内部的返回函数替代。对于复杂的状态逻辑,请使用 useReducer。

自动迁移工具 — @phenomnomnominal/ts-react-class-to-hook 或 codemod 脚本 — 可以自动转换简单的类。对于复杂情况,迁移仍然是需要理解原始组件逻辑的手动工作。

常见问题

在构造函数中调用 super(props) 是必需的吗?

是的。super(props) 将 props 传递给父级 React.Component。如果没有这个调用,this.props 在构造函数内部将是 undefined。在 render 和生命周期方法中,即使没有 super,props 也是可用的,但这是实现的副作用。

为什么 setState 是异步的?

React 将多个 setState 调用分组到一个批次中,以减少不必要的重新渲染次数。如果 setState 是同步的,每次调用都会导致立即渲染,降低批量更新时的性能。

可以在类组件内部使用 hooks 吗?

不能。Hooks 只在函数式组件中工作。对于具有类组件的项目,所有旧模式都可用:render props、HOC 和用于上下文的 Consumer。迁移到 hooks 需要将类转换为函数。

什么是 PureComponent?它与 Component 有什么不同?

React.PureComponent 使用浅比较(shallow)props 和状态来实现 shouldComponentUpdate。与始终在 setState 时重新渲染的 Component 不同,如果数据没有更改,PureComponent 会跳过重新渲染。这是对没有复杂嵌套的组件的优化。

如何在类组件中处理错误?

使用 componentDidCatchgetDerivedStateFromError。componentDidCatch(error, info) 记录错误。getDerivedStateFromError 更新状态以显示备用 UI。这些方法仅在类组件中工作 — 函数需要一个 ErrorBoundary 包装组件。

总结

  • React.Component — 具有继承、状态和生命周期方法的组件的基础类。
  • this.state 在构造函数中初始化,仅通过 this.setState 更新 — 禁止直接修改。
  • componentDidMount — 首次渲染后 API 请求、订阅和定时器的主要位置。
  • componentWillUnmount — 强制清理订阅和定时器以防止内存泄漏。
  • this 绑定是必需的:在构造函数中使用 bind — 推荐用于回调方法的方式。
  • Hooks 已取代类组件用于新项目,但类仍然完全受支持。
  • 迁移到 hooks 逐步进行:首先是 stateless 组件,复杂的 — 通过 useReducer 和 useEffect。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读