React 类组件与函数式组件

你想了解的类组件(Class Component)和函数式组件(Functional Component)是 React 中两种核心的组件编写方式,前者是 React 早期的主流方案,后者则在 Hooks 推出后成为官方推荐的首选。本文会从语法结构、状态管理、生命周期、性能、使用场景等维度,帮你理清二者的核心区别,以及不同场景下的选型思路。

一、核心定义与语法差异

1. 类组件(Class Component)

类组件是基于 ES6 类语法创建的组件,必须继承React.ComponentReact.PureComponent,并通过render()方法返回 JSX。

jsx

复制代码
import React from 'react';

// 类组件示例
class ClassCounter extends React.Component {
  // 构造函数:初始化状态、绑定方法
  constructor(props) {
    super(props);
    // 初始化state
    this.state = { count: 0 };
    // 手动绑定this(避免回调中this丢失)
    this.handleIncrement = this.handleIncrement.bind(this);
  }

  // 自定义方法
  handleIncrement() {
    // 修改状态(必须用setState)
    this.setState({ count: this.state.count + 1 });
  }

  // 必须实现render方法
  render() {
    return (
      <div>
        <p>计数:{this.state.count}</p>
        <button onClick={this.handleIncrement}>+1</button>
      </div>
    );
  }
}

2. 函数式组件(Functional Component)

函数式组件本质是一个普通的 JavaScript 函数,接收props作为参数,直接返回 JSX。Hooks(React 16.8+)推出后,函数式组件才具备了状态管理和生命周期能力。

jsx

复制代码
import React, { useState } from 'react';

// 函数式组件示例
function FunctionalCounter(props) {
  // 用useState Hook管理状态
  const [count, setCount] = useState(0);

  // 自定义方法(无需绑定this)
  const handleIncrement = () => {
    // 直接修改状态
    setCount(count + 1);
  };

  // 直接返回JSX,无需render方法
  return (
    <div>
      <p>计数:{count}</p>
      <button onClick={handleIncrement}>+1</button>
    </div>
  );
}

二、核心区别对比

为了让你更清晰地对比,我整理了关键维度的差异表:

对比维度 类组件(Class Component) 函数式组件(Functional Component)
语法结构 基于 ES6 Class,需继承 React.Component 普通 JS 函数,语法更简洁,无冗余代码
状态管理 this.statesetState()管理状态 useState/useReducer Hooks 管理状态
this 指向 存在 this,需手动绑定(或用箭头函数) 无 this,避免 this 指向混乱问题
生命周期 有明确的生命周期方法(componentDidMount 等) useEffect Hook 模拟所有生命周期逻辑
性能优化 可继承PureComponent或实现shouldComponentUpdate React.memo(浅比较 props)+ useMemo/useCallback优化
代码复用 依赖高阶组件(HOC)、Render Props 依赖 Hooks(更简洁,无嵌套地狱)
错误边界 仅类组件可作为错误边界(实现 componentDidCatch) 无法直接作为错误边界(需包裹类组件)
官方推荐 仅兼容老项目,不推荐新开发 React 16.8 + 官方首选方案

三、关键能力深度解析

1. 状态管理差异

类组件
  • 状态是对象形式this.state = { count: 0, name: 'test' }

  • 修改状态必须用setState(),且setState异步更新 (合成事件中),可能需要依赖前一个状态:

    jsx

    复制代码
    // 正确:依赖前状态更新
    this.setState(prevState => ({ count: prevState.count + 1 }));
  • 无法在函数中直接捕获最新状态(需用 ref 或 setState 回调)。

函数式组件
  • 状态可以是任意类型 (数字、字符串、对象、数组等),useState按需求拆分:

    jsx

    复制代码
    const [count, setCount] = useState(0);
    const [user, setUser] = useState({ name: '张三' });
  • setState直接替换 (而非合并),更新对象 / 数组时需手动合并:

    jsx

    复制代码
    // 更新对象:合并原有属性
    setUser(prev => ({ ...prev, age: 25 }));
  • 能通过闭包直接捕获最新状态(但需注意依赖项问题)。

2. 生命周期模拟(函数式组件 vs 类组件)

类组件的生命周期方法在函数式组件中都能通过useEffect模拟,对应关系如下:

类组件生命周期 函数式组件实现方式
componentDidMount useEffect (() => { /* 逻辑 */ }, [])
componentDidUpdate useEffect (() => { /* 逻辑 */ }, [依赖项])
componentWillUnmount useEffect (() => { return () => { /* 清理 */ } }, [])
componentDidMount + componentDidUpdate useEffect (() => { /* 逻辑 */ })

示例:模拟类组件的生命周期

jsx

复制代码
// 函数式组件模拟生命周期
function LifecycleDemo() {
  const [count, setCount] = useState(0);

  // componentDidMount:仅挂载时执行
  useEffect(() => {
    console.log('组件挂载');
    // componentWillUnmount:清理函数
    return () => {
      console.log('组件卸载');
    };
  }, []);

  // componentDidUpdate:count变化时执行
  useEffect(() => {
    console.log('count更新为:', count);
  }, [count]);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

3. 性能优化差异

类组件优化
  • 继承React.PureComponent:自动对propsstate浅比较,避免不必要的重渲染;
  • 手动实现shouldComponentUpdate:自定义比较逻辑,返回false阻止重渲染。
函数式组件优化
  • React.memo:高阶组件,对props做浅比较,类似PureComponent
  • useMemo:缓存计算结果,避免每次渲染重复计算;
  • useCallback:缓存函数引用,避免因函数重新创建导致子组件重渲染。

示例:函数式组件性能优化

jsx

复制代码
// React.memo:浅比较props
const MemoizedChild = React.memo(({ onIncrement }) => {
  console.log('子组件渲染');
  return <button onClick={onIncrement}>+1</button>;
});

function Parent() {
  const [count, setCount] = useState(0);
  
  // useCallback:缓存函数引用
  const handleIncrement = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  // useMemo:缓存计算结果
  const doubleCount = useMemo(() => {
    return count * 2;
  }, [count]);

  return (
    <div>
      <p>计数:{count},双倍:{doubleCount}</p>
      <MemoizedChild onIncrement={handleIncrement} />
    </div>
  );
}

四、使用场景与选型建议

1. 优先使用函数式组件的场景

  • 新项目开发:React 官方推荐,代码更简洁、易维护;
  • 需要复用逻辑 :Hooks(如useStateuseEffect、自定义 Hook)比 HOC/Render Props 更优雅;
  • 团队协作:降低学习成本(无需理解 this、生命周期),减少 bug;
  • 性能敏感场景 :通过React.memo+useCallback/useMemo可精准优化。

2. 仍需使用类组件的场景

  • 维护老项目:老代码基于类组件,无需强行重构;

  • 实现错误边界 :函数式组件无法直接实现componentDidCatch,需用类组件:

    jsx

    复制代码
    class ErrorBoundary extends React.Component {
      state = { hasError: false };
      static getDerivedStateFromError() {
        return { hasError: true };
      }
      componentDidCatch(error, info) {
        console.log('捕获错误:', error, info);
      }
      render() {
        if (this.state.hasError) {
          return <div>出错了!</div>;
        }
        return this.props.children;
      }
    }
    // 使用:包裹函数式组件
    <ErrorBoundary>
      <FunctionalComponent />
    </ErrorBoundary>
  • 极少数复杂场景 :如需要深度定制shouldComponentUpdate且 Hooks 优化成本更高。

五、迁移指南(类组件 → 函数式组件)

如果需要将类组件迁移为函数式组件,可遵循以下步骤:

  1. 替换类定义为函数 :移除classextends React.Component,改为函数接收props
  2. 替换 state :将this.state拆分为多个useState
  3. 替换生命周期 :用useEffect模拟componentDidMount/DidUpdate/WillUnmount
  4. 移除 this 绑定:函数内方法无需绑定 this,直接定义箭头函数或普通函数;
  5. 替换 this.props :直接使用函数参数props
  6. 性能优化 :用React.memo替代PureComponentuseCallback/useMemo替代手动优化。

迁移示例

jsx

复制代码
// 类组件
class OldComponent extends React.Component {
  state = { text: '' };
  componentDidMount() {
    console.log('挂载');
  }
  handleChange = (e) => {
    this.setState({ text: e.target.value });
  };
  render() {
    return <input value={this.state.text} onChange={this.handleChange} />;
  }
}

// 迁移后的函数式组件
function NewComponent(props) {
  const [text, setText] = useState('');
  
  useEffect(() => {
    console.log('挂载');
  }, []);

  const handleChange = (e) => {
    setText(e.target.value);
  };

  return <input value={text} onChange={handleChange} />;
}
// 性能优化:添加React.memo
const MemoizedNewComponent = React.memo(NewComponent);

总结

  1. 核心差异 :类组件基于 ES6 Class,依赖this和生命周期方法;函数式组件是纯函数,依赖 Hooks 实现状态和生命周期,语法更简洁、无 this 陷阱。
  2. 选型原则:新项目优先用函数式组件 + Hooks,老项目 / 错误边界场景保留类组件。
  3. 优化方式 :类组件用PureComponent/shouldComponentUpdate,函数式组件用React.memo+useCallback/useMemo

掌握二者的区别和选型思路,能让你在 React 开发中更灵活地选择合适的组件形式,写出更高效、易维护的代码。

👉 **觉得有用的点点关注谢谢~**

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax