创见博客
React中的类组建
七崽爱吃小饼干2026/01/04阅读 1专栏 React

React 类组件详解

一、类组件的核心定义

React 类组件是基于 ES6 Class 语法创建的 React 组件,它必须满足两个核心条件:

  1. 继承自 React.Component(或 React.PureComponent,后续会说明差异)
  2. 必须定义 render() 方法(唯一强制要求的生命周期方法),用于返回组件要渲染的 JSX 内容

基础结构示例

jsx
import React from 'react';

// 类组件的基础写法
class Greeting extends React.Component {
  // render() 方法:必须存在,负责渲染视图
  render() {
    // 通过 this.props 接收父组件传递的属性
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

// 使用类组件
function App() {
  return <Greeting name="React 类组件" />;
}

export default App;

二、类组件的状态(State)管理

类组件拥有自身的内部状态(State),用于存储组件自身需要维护的数据,这是类组件与早期函数组件(无 Hooks)的核心区别之一。

1. State 的初始化

有两种常用初始化方式:

  • 方式1:在类的构造函数(constructor)中初始化(传统写法,支持访问 props)
  • 方式2:直接在类体中定义(ES7 语法,更简洁,推荐)
jsx
class Counter extends React.Component {
  // 方式2:简洁初始化(推荐)
  state = {
    count: 0, // 初始化计数器状态
    message: this.props.initMsg // 可直接访问 props
  };

  // 方式1:构造函数初始化(传统写法,需调用 super(props))
  // constructor(props) {
  //   super(props); // 必须先调用父类构造函数,否则无法访问 this.props
  //   this.state = {
  //     count: 0,
  //     message: props.initMsg
  //   };
  // }

  render() {
    return (
      <div>
        <p>计数:{this.state.count}</p>
        <p>提示:{this.state.message}</p>
      </div>
    );
  }
}

2. State 的更新:setState() 方法

注意:绝对不能直接修改 this.state(如 this.state.count = 1),这种写法不会触发组件重新渲染,React 要求通过 setState() 方法更新状态。

setState() 有两种用法:

  • 用法1:对象式更新(适用于状态更新不依赖于当前状态)
  • 用法2:函数式更新(适用于状态更新依赖于当前状态,如累加、递减)
jsx
class Counter extends React.Component {
  state = { count: 0 };

  // 对象式更新:不依赖当前状态
  increment = () => {
    this.setState({ count: this.state.count + 1 });
    // 注意:setState 是异步的!若需在状态更新后执行操作,可传入第二个回调参数
    // this.setState({ count: this.state.count + 1 }, () => {
    //   console.log("状态更新后的count:", this.state.count);
    // });
  };

  // 函数式更新:依赖当前状态(推荐,避免异步更新导致的误差)
  decrement = () => {
    this.setState((prevState, props) => {
      // prevState:更新前的状态;props:当前组件的 props
      return { count: prevState.count - 1 };
    });
  };

  render() {
    return (
      <div>
        <p>计数:{this.state.count}</p>
        <button onClick={this.increment}>+1</button>
        <button onClick={this.decrement}>-1</button>
      </div>
    );
  }
}

关键特性:setState() 是异步执行的,React 会批量合并状态更新以提升性能。

三、类组件的生命周期(核心知识点)

类组件的生命周期分为三个核心阶段,每个阶段对应不同的生命周期方法,用于在组件不同阶段执行特定逻辑。

1. 挂载阶段(Mount):组件首次渲染到 DOM 中

执行顺序:constructor() → render() → componentDidMount()

  • constructor(props):组件构造函数,用于初始化 state、绑定事件处理函数(若不使用箭头函数)
  • render():渲染 JSX 到虚拟 DOM,此时尚未挂载到真实 DOM
  • componentDidMount():组件已挂载到真实 DOM 后执行
    • 常用场景:发起网络请求(接口调用)、初始化第三方库(如 ECharts)、添加定时器等
jsx
class UserList extends React.Component {
  state = { users: [] };

  componentDidMount() {
    // 组件挂载后发起接口请求
    fetch('https://api.example.com/users')
      .then(res => res.json())
      .then(data => this.setState({ users: data }))
      .catch(err => console.error(err));
  }

  render() {
    return (
      <ul>
        {this.state.users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    );
  }
}

2. 更新阶段(Update):组件因 props 变化或 state 更新而重新渲染

执行顺序:render() → componentDidUpdate(prevProps, prevState, snapshot)

  • 触发更新的原因:
    1. 自身 state 被 setState() 更新
    2. 父组件传递的 props 发生变化
    3. 手动调用 forceUpdate()(不推荐,会跳过 shouldComponentUpdate 优化)
  • componentDidUpdate:组件更新完成后执行
    • 接收三个参数:更新前的 props、更新前的 state、快照(来自 getSnapshotBeforeUpdate)
    • 常用场景:根据 props 变化重新发起请求、更新第三方库配置
jsx
class UserDetail extends React.Component {
  state = { user: null };

  componentDidMount() {
    this.fetchUser(this.props.userId);
  }

  // 组件更新后,若 userId 变化,重新请求用户信息
  componentDidUpdate(prevProps) {
    if (prevProps.userId !== this.props.userId) {
      this.fetchUser(this.props.userId);
    }
  }

  fetchUser = (id) => {
    fetch(`https://api.example.com/users/${id}`)
      .then(res => res.json())
      .then(data => this.setState({ user: data }));
  };

  render() {
    if (!this.state.user) return <div>加载中...</div>;
    return <div>用户名:{this.state.user.name}</div>;
  }
}

3. 卸载阶段(Unmount):组件从 DOM 中移除

仅一个生命周期方法:componentWillUnmount()

  • 执行时机:组件即将被卸载并销毁前
  • 常用场景:清理副作用,如清除定时器、取消网络请求、解绑第三方库事件等
jsx
class Timer extends React.Component {
  state = { time: 0 };
  timerId = null;

  componentDidMount() {
    // 初始化定时器
    this.timerId = setInterval(() => {
      this.setState(prevState => ({ time: prevState.time + 1 }));
    }, 1000);
  }

  componentWillUnmount() {
    // 组件卸载前清除定时器,防止内存泄漏
    clearInterval(this.timerId);
  }

  render() {
    return <div>已计时:{this.state.time} 秒</div>;
  }
}

补充:优化型生命周期方法

  • shouldComponentUpdate(nextProps, nextState):更新阶段的前置钩子,返回布尔值
    • 返回 true(默认):允许组件更新;返回 false:阻止组件更新
    • 常用场景:手动优化性能,避免不必要的重新渲染
  • React.PureComponent:继承自 React.Component,自动实现了 shouldComponentUpdate 的浅比较(对比 props 和 state 的浅层属性),无需手动编写优化逻辑(注意:仅支持浅比较,深层对象变化无法检测)

四、类组件的事件处理

类组件的事件处理函数有两个注意点:

  1. 事件处理函数中的 this 指向问题(默认情况下,类方法中的 this 为 undefined)
  2. 事件绑定的三种解决方案

解决方案1:箭头函数(推荐,最简洁)

jsx
class Button extends React.Component {
  handleClick = () => {
    // 箭头函数自动绑定 this,指向组件实例
    console.log("按钮被点击", this.props.title);
  };

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

解决方案2:构造函数中绑定 this

jsx
class Button extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this); // 手动绑定 this
  }

  handleClick() {
    console.log("按钮被点击", this.props.title);
  }

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

解决方案3:渲染时使用箭头函数(不推荐,每次渲染会创建新函数)

jsx
class Button extends React.Component {
  handleClick() {
    console.log("按钮被点击", this.props.title);
  }

  render() {
    // 每次 render 都会创建新的箭头函数,可能影响性能
    return <button onClick={() => this.handleClick()}>{this.props.title}</button>;
  }
}

五、类组件 vs 函数组件(Hooks)

随着 React 16.8 推出 Hooks,函数组件已成为主流,但类组件仍有一定的历史使用场景,两者核心差异如下:

特性类组件函数组件(Hooks)
状态管理基于 this.state基于 useState/useReducer
生命周期明确的生命周期方法基于 useEffect 模拟
this 指向存在绑定问题无 this,无需处理绑定
代码简洁性代码冗余,模板化代码简洁,逻辑内聚
复用逻辑高阶组件(HOC)/Render Props自定义 Hooks(更优雅)
性能优化shouldComponentUpdate/PureComponentReact.memo/useMemo/useCallback

六、类组件的局限性(为何现在优先使用函数组件)

  1. this 指向问题:增加了学习成本和潜在的 bug
  2. 代码冗余:生命周期方法容易导致逻辑分散(如网络请求在 componentDidMount,更新请求在 componentDidUpdate)
  3. 逻辑复用困难:高阶组件和 Render Props 会增加组件嵌套层级("嵌套地狱")
  4. 难以实现复杂逻辑:对于异步状态管理、上下文消费等场景,代码可读性较差

总结

  1. React 类组件是基于 ES6 Class 继承 React.Component 的组件,必须包含 render() 方法
  2. 内部状态通过 this.state 初始化,通过 setState() 异步更新(支持对象式和函数式两种写法)
  3. 生命周期分为挂载、更新、卸载三个阶段,核心方法有 componentDidMount、componentDidUpdate、componentWillUnmount
  4. 事件处理需解决 this 绑定问题,推荐使用箭头函数
  5. 类组件已逐渐被函数组件(Hooks)替代,但在老项目维护中仍需掌握
  6. 核心差异:类组件依赖 this 和生命周期,函数组件依赖 Hooks,代码更简洁、逻辑更易复用
评论
0/100