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 开发中更灵活地选择合适的组件形式,写出更高效、易维护的代码。

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

相关推荐
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-成绩管理功能实现方案
开发语言·前端·javascript·人工智能·spring boot
幻云20102 小时前
Python深度学习:从筑基与巅峰
前端·javascript·vue.js·人工智能·python
Light602 小时前
庖丁解牛:深入JavaScript内存管理,从内存泄漏到AI赋能的性能优化
javascript·人工智能·性能优化·内存管理·垃圾回收·内存泄漏·v8引擎
_OP_CHEN2 小时前
【前端开发之HTML】(三)HTML 常见标签(下):图文、链接与实战,解锁网页交互新姿势!
前端·html·交互·前端开发·网页开发·界面美化
334554322 小时前
vue表格遍历根据表头里的类型和每行的状态来判断
javascript·vue.js·chrome
岳哥i10 小时前
vue鼠标单机复制文本
javascript
jacGJ10 小时前
记录学习--文件读写
java·前端·学习
毕设源码-赖学姐11 小时前
【开题答辩全过程】以 基于WEB的实验室开放式管理系统的设计与实现为例,包含答辩的问题和答案
前端
幻云201011 小时前
Python深度学习:从筑基到登仙
前端·javascript·vue.js·人工智能·python