如题,react的组件分为类组件和函数组件。但二者有什么区别呢?

我刚开始的时候,无端的认为,只有类组件可以输出DOM,函数组件只能充当函数库之类的角色。但事实上,它们的功能是差不多的。从资料看,似乎是类组件先出现,后来才有的函数组件。二者最大的区别,也许是类组件比较笨重,函数组件比较轻盈,大有后来居上之势。类组件的优势,在于拥有时间周期事件函数,但函数组件也可以通过Hook函数实现相同的效果。

下面是二者的一些比较:

一、定义方式

在 React 中,类组件和函数组件是两种不同的组件定义方式。它们各有特点,适用于不同的场景。下面是它们之间的一些主要区别:

1. 类组件(Class Component)

类组件是使用 ES6 的类(class)语法定义的 React 组件。它们具有更复杂的功能,特别是在 React 16.8 之前,它们是唯一能够使用状态(state)和生命周期方法的组件。

特点:

使用 class 关键字定义,并继承自 React.Component。
能够使用 state 来管理组件的内部状态。
可以使用生命周期方法,如 componentDidMount、componentDidUpdate 和 componentWillUnmount 等。
通过 this.props 来访问传递给组件的属性(props)。

import React, { Component } from 'react';

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

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

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

export default MyComponent;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

2. 函数组件(Function Component)

函数组件是使用 JavaScript 函数定义的 React 组件。自 React 16.8 以来,函数组件通过引入 Hooks 可以实现状态管理和副作用处理,功能上已经与类组件基本等价。

特点:

使用 JavaScript 函数定义,通常是更简单和推荐的方式。
在函数组件中,无法直接使用 this,而是通过 Hooks(如> useState 和 useEffect)来管理状态和副作用。
更加简洁,通常用于无状态组件,但在有状态需求时也可以使用 Hooks。

import React, { useState } from 'react';

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

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

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

export default MyComponent;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

二. 状态管理

类组件:
使用 this.state 来管理组件的状态。
使用 this.setState() 方法来更新状态。
可以在生命周期方法中使用 setState 来响应不同的事件。

函数组件:
使用 useState Hook 来管理状态。
使用 useReducer Hook 来管理更复杂的状态逻辑。
可以在函数组件内部使用多个 useState 或 useReducer 来管理不同的状态片段。

三. 生命周期方法

类组件:
提供了一系列的生命周期方法,如 componentDidMount, componentDidUpdate, componentWillUnmount 等。
可以在这些方法中执行副作用操作,如数据获取、订阅等。

函数组件:
使用 useEffect Hook 来执行副作用操作。
可以模拟类组件的生命周期方法,例如在 useEffect 中模拟 componentDidMount 和 componentDidUpdate。

四. 代码结构

类组件:
通常包含多个方法和生命周期钩子,可能会导致组件变得复杂。
需要更多样板代码(如构造函数、render 方法等)。

函数组件:
结构更简单,更易于理解和维护。
使用 Hooks 可以保持逻辑的一致性,使组件更加模块化。

五. 可复用性

类组件:
通常使用高阶组件(Higher Order Components, HOCs)或渲染属性模式来复用逻辑。
可能需要提取子类来复用逻辑。

函数组件:
使用 Hooks 如 useCallback, useMemo, useContext 等来复用逻辑。
可以定义自定义 Hooks 来封装复用的逻辑。

六. 性能考虑

类组件:
在某些情况下,可能会因为额外的实例方法和生命周期方法而稍微影响性能。
使用纯组件 (React.PureComponent) 可以提高性能,因为它会自动进行浅比较以避免不必要的重新渲染。

函数组件:
使用 React.memo 或 useMemo 可以提高性能,减少不必要的渲染。
使用 useCallback 可以确保函数引用的一致性,从而避免不必要的渲染。

七. 语法糖

在 React 中,propTypes 和 defaultProps 用于类型检查和为组件的 props 提供默认值。类组件和函数组件在使用这些特性时有些细微的区别。

类组件:
可以直接使用 propTypes 和 defaultProps。
propTypes:用于检查传入 props 的类型是否符合预期。
defaultProps:用于定义组件的默认 props 值,如果没有传递该 prop,会使用默认值。

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class MyClassComponent extends Component {
  // 定义 propTypes
  static propTypes = {
    message: PropTypes.string,
    count: PropTypes.number
  };

  // 定义 defaultProps
  static defaultProps = {
    message: 'Hello',
    count: 0
  };

  render() {
    return (
      <div>
        <p>{this.props.message}</p>
        <p>{this.props.count}</p>
      </div>
    );
  }
}

export default MyClassComponent;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

函数组件:

1)可以使用 PropTypes 作为单独的导入,或者使用 React.memo 的第二个参数来定义 propTypes 和 defaultProps。

import React from 'react';
import PropTypes from 'prop-types';

function MyFunctionComponent(props) {
  return (
    <div>
      <p>{props.message}</p>
      <p>{props.count}</p>
    </div>
  );
}

// 定义 propTypes
MyFunctionComponent.propTypes = {
  message: PropTypes.string,
  count: PropTypes.number
};

// 定义 defaultProps
MyFunctionComponent.defaultProps = {
  message: 'Hello',
  count: 0
};

export default MyFunctionComponent;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

2)使用 React.memo 包装

import React from 'react';
import PropTypes from 'prop-types';

const MyFunctionComponent = React.memo(function(props) {
  return (
    <div>
      <p>{props.message}</p>
      <p>{props.count}</p>
    </div>
  );
});

// 定义 propTypes
MyFunctionComponent.propTypes = {
  message: PropTypes.string,
  count: PropTypes.number
};

// 定义 defaultProps
MyFunctionComponent.defaultProps = {
  message: 'Hello',
  count: 0
};

export default MyFunctionComponent;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

八.this

在函数组件中不能使用 this,因为 this 是类组件的概念

九.总结

类组件 vs. 函数组件

代码简洁性:函数组件通常比类组件更简洁。
状态管理:类组件通过 this.state 和 this.setState 管理状态,而函数组件使用 useState 钩子。
生命周期管理:类组件使用生命周期方法,而函数组件使用 useEffect 钩子(Hook)来管理副作用。
性能:函数组件在大多数情况下具有更好的性能,因为它们不需要 this 的绑定操作,并且在 React 的渲染机制中更容易优化。

类组件和函数组件都可以有效地构建 React 应用程序,但函数组件配合 Hooks 的使用已经成为了 React 社区中的主流趋势。函数组件因其简洁性和可维护性而受到青睐,而 Hooks 为函数组件提供了类似类组件的功能,同时也增加了更多的灵活性和可复用性。

随着React Hooks的引入,函数组件已经能够完成大部分类组件能做的事情,并且代码更简洁、更容易理解。因此,建议默认使用函数组件,特别是对于新项目或新功能开发。不过,在需要使用生命周期方法或维护遗留代码时,类组件仍然是合适的选择。