Component API

React.Component 是类组件的基础 API,提供生命周期方法和状态管理。

概述

React.Component 是使用 ES6 class 定义 React 组件时的基类。 它提供了完整的生命周期方法、状态管理和上下文访问。

💡 提示: 如果你不需要类组件的完整功能, 推荐使用函数组件和 Hooks,它们更简洁且易于理解。

基本用法

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

类声明

要定义一个 React 组件类,需要继承 React.Component:

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

生命周期方法

组件生命周期分为三个主要阶段:挂载、更新和卸载。

挂载 (Mounting)

这些方法在组件实例被创建和插入 DOM 时按顺序调用:

  • constructor() - 构造函数
  • static getDerivedStateFromProps() - 从 props 派生状态
  • render() - 渲染 UI
  • componentDidMount() - 组件挂载后

更新 (Updating)

当组件的 props 或 state 发生变化时:

  • static getDerivedStateFromProps() - 从 props 派生状态
  • shouldComponentUpdate() - 是否应该更新
  • render() - 渲染 UI
  • getSnapshotBeforeUpdate() - 更新前获取快照
  • componentDidUpdate() - 组件更新后

卸载 (Unmounting)

当组件从 DOM 中移除时:

  • componentWillUnmount() - 组件卸载前

错误处理 (Error Handling)

当渲染过程、生命周期方法或子组件构造函数中抛出错误时:

  • static getDerivedStateFromError() - 从错误中恢复
  • componentDidCatch() - 捕获错误

常用生命周期详解

render()

render() 方法是类组件中唯一必须的方法。

render() {
  return (
    <div>
      <h1>{this.props.title}</h1>
      <p>{this.state.description}</p>
    </div>
  );
}

⚠️ 注意: render() 应该是纯函数,不应修改 state、 不直接与浏览器交互,应该在 componentDidMount() 中进行这些操作。

constructor(props)

用于初始化状态和绑定事件处理程序。

constructor(props) {
  super(props);
  // 不要在这里调用 this.setState()
  this.state = {
    count: 0
  };
  // 绑定事件处理程序
  this.handleClick = this.handleClick.bind(this);
}

✅ 最佳实践: 避免在 constructor() 中引入副作用或订阅。 这些操作应该在 componentDidMount() 中进行。

componentDidMount()

在组件挂载后立即调用,是进行副作用操作的最佳位置。

componentDidMount() {
  // 数据获取
  fetchUserData().then(data => {
    this.setState({ user: data });
  });

  // 订阅
  this.subscription = dataSource.subscribe(
    this.handleChange
  );
}

componentWillUnmount() {
  // 清理订阅
  this.subscription.unsubscribe();
}

componentDidUpdate(prevProps, prevState, snapshot)

在更新后立即调用,首次渲染不会调用。

componentDidUpdate(prevProps) {
  // 典型用法:当 props 变化时获取数据
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

⚠️ 注意: 可以在 componentDidUpdate() 中调用 setState(), 但必须包含在条件语句中,否则会导致无限循环。

componentWillUnmount()

在组件卸载和销毁之前立即调用。

componentWillUnmount() {
  // 清理定时器
  clearInterval(this.timerID);

  // 取消网络请求
  this.abortController.abort();

  // 清理订阅
  this.subscription.unsubscribe();
}

完整示例

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>当前时间</h1>
        <h2>{this.state.date.toLocaleTimeString()}</h2>
      </div>
    );
  }
}

最佳实践

✅ 推荐做法

  • 使用 setState() 而不是直接修改 state
  • 在 componentWillUnmount() 中清理副作用
  • 当不需要 state 或生命周期方法时使用函数组件
  • 使用 PropTypes 进行类型检查

❌ 避免做法

  • 在 render() 中调用 setState()
  • 在 constructor() 中进行副作用操作
  • 忘记在 componentWillUnmount() 中清理
  • 直接修改 this.state

迁移到函数组件

React 推荐使用函数组件和 Hooks 替代类组件。 以下是迁移示例:

类组件

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

  increment = () => {
    this.setState(state => ({
      count: state.count + 1
    }));
  }

  render() {
    return (
      <button onClick={this.increment}>
        Count: {this.state.count}
      </button>
    );
  }
}

函数组件 + Hooks

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(c => c + 1);
  };

  return (
    <button onClick={increment}>
      Count: {count}
    </button>
  );
}

相关 API