React 函数组件和类组件,为什么函数组件更好

何谓类组件(Class Component)

基于 ES6 Class 这种写法,通过继承 React.Component 得来的 React 组件。

代码:

class DemoClass extends React.Component {
  // 初始化类组件的 state
  state = {
    text: ""
  };


  componentDidMount() {
    // 省略业务逻辑
  }

  changeText = (newText) => {
    // 更新 state
    this.setState({
      text: newText
    });
  };

  // 编写生命周期方法 render
  render() {
    return (
      <div>
        <p>{this.state.text}</p>
        <button onClick={()=>this.changeText("newText")}>修改</button>
      </div>
    );
  }
}

特点

  • 为了避免代码冗余,提高代码利用率,组件可以重复调用
  • 组件的属性props是只读的,调用者可以传递参数到props对象中定义属性,调用者可以直接将属性作为组件内的属性或方法直接调用。往往是组件调用方调用组件时指定props定义属性,往往定值后就不改边了,注意组件调用方可赋值被调用方。
  • 通过props的方式进行父子组件交互,通过传递一个新的props属性值使得子组件重新render,从而达到父子组件通讯。
  • {…this.props}可以传递属性集合,…为属性扩展符
  • 组件必须返回了一个 React 元素
  • 组件中state为私有属性,是可变的,一般在construct()中定义,使用方法:不要直接修改 state(状态)
  • 修改子组件还有一种方式,通过 ref属性,表示为对组件真正实例引用,其实就是ReactDOM.render()返回的组件实例

函数组件

何谓函数组件/无状态组件(Function Component/Stateless Component)

函数组件顾名思义,就是以函数的形态存在的 React 组件。早期并没有 React-Hooks 的加持,函数组件内部无法定义和维护 state,因此它还有一个别名叫“无状态组件”。以下是一个典型的函数组件:

function DemoFunction(props) {
  const { text } = props
  return (
    <div className="demoFunction">
      <p>{`function 组件所接收到的来自外界的文本内容是:[${text}]`}</p>
    </div>
  );
}

特点

  • 只负责接收 props,渲染 DOM
  • 没有 state
  • 返回了一个 React 元素
  • 不能访问生命周期方法
  • 不需要声明类:可以避免 extends 或 constructor 之类的代码,语法上更加简洁。
  • 不会被实例化:因此不能直接传 ref(可以使用 React.forwardRef 包装后再传 ref)。
  • 不需要显示声明 this 关键字:在 ES6 的类声明中往往需要将函数的 this 关键字绑定到当前作用域,而因为函数式声明的特性,我们不需要再强制绑定。
  • 更好的性能表现:因为函数式组件中并不需要进行生命周期的管理与状态管理,因此React并不需要进行某些特定的检查或者内存分配,从而保证了更好地性能表现。

共同点

  • 接收值:都一样接收了一个只读的 props
  • 返回值:都是返回了一个 React 元素

不同点

设计思想层面

  • 类组件的根基是 OOP(面向对象编程),所以它有继承、有属性、有内部状态的管理。
  • 函数组件的根基是 FP (函数式编程)。它属于“结构化编程”的一种,与数学函数思想类似。也就是假定输入与输出存在某种特定的映射关系,那么输入一定的情况下,输出必然是确定的。

渲染差异

函数组件会捕获render内部的状态

具体文章参见:React 作者 Dan的文章How Are Function Components Different from Classes

能力

  • 类组件通过生命周期包装业务逻辑

  • 函数组件可以通过React Hooks 钩子函数来模拟类组件中的生命周期(useState ,useEffect,useContext,useCallback 等)

  • Hooks 的本质:一套能够使函数组件更强大、更灵活的“钩子”

使用场景

  • 在不使用 Recompose 或者 Hooks 的情况下,如果需要使用生命周期,那么就用类组件,限定的场景是非常固定的;

  • 但在 recompose 或 Hooks 的加持下,这样的边界就模糊化了,类组件与函数组件的能力边界是完全相同的,都可以使用类似生命周期等能力。

设计模式

在设计模式上,因为类本身的原因,类组件是可以实现继承的,而函数组件缺少继承的能力。

当然在 React 中也是不推荐继承已有的组件的,因为继承的灵活性更差,细节屏蔽过多,所以有这样一个铁律,组合优于继承

发展趋势

函数组件更加契合 React 框架的设计理念

React 组件本身的定位就是函数,一个吃进数据、吐出 UI 的函数。作为开发者,我们编写的是声明式的代码,而 React 框架的主要工作,就是及时地把声明式的代码转换为命令式的 DOM 操作,把数据层面的描述映射到用户可见的 UI 变化中去。这就意味着从原则上来讲,React 的数据应该总是紧紧地和渲染绑定在一起的,而类组件做不到这一点。

由于 React Hooks 的推出,函数组件成了社区未来主推的方案。

React 团队从 Facebook 的实际业务出发,通过探索时间切片与并发模式,以及考虑性能的进一步优化与组件间更合理的代码拆分结构后,认为类组件的模式并不能很好地适应未来的趋势。 他们给出了3 个原因:

  • this 的模糊性;
  • 业务逻辑散落在生命周期中;
  • React 的组件代码缺乏标准的拆分方式。

而使用 Hooks 的函数组件可以提供比原先更细粒度的逻辑组织与复用,且能更好地适用于时间切片与并发模式。

请登录后发表评论

    没有回复内容