为什么React要用函数式组件?

1,425 阅读3分钟

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

首先对比一下以往的函数式组件和类式组件的不同。

类式组件函数式组件
需要继承不需要
有生命周期方法不可以
可以定义且维护state不可以
可以获取到实例的this,而且可以根据this去做事不可以
......

类式组件

先来看看类式组件

class DemoClass extends React.Component {
  // 初始化类组件的 state
  state = {
    text: ""
  };
  // 编写生命周期方法 didMount
  componentDidMount() {
    // 省略业务逻辑
  }
  // 编写自定义的实例方法
  changeText = (newText) => {
    // 更新 state
    this.setState({
      text: newText
    });
  };
  // 编写生命周期方法 render
  render() {
    return (
      <div className="demoClass">
        <p>{this.state.text}</p>
        <button onClick={this.changeText}>点我修改</button>
      </div>
    );
  }
}

类式组件中有state,生命周期,像是一个全副武装的战舰,但是大的同时也让你的学习成本变得很高,而且复杂的同时难以拆解和复用,可能你需要学习高阶组件,RenderProps,用更高的成本来交换编码的灵活度。

函数式组件

相比较于类式组件,函数式组件更像式一艘快艇。

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

同时他们之间有一个核心的差别

就是函数式组件可以捕获render内部的状态,这是两种组件最大的不同。

而且从思想上说,是面向对象和函数式编程的两种思想的差异。

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

React本身的定位就像是一个吃进数据,吐出UI的函数。因此,React需要将数据和渲染紧紧的绑定到一起,让数据去驱动渲染,也就是state => view,而类组件是做不到这一点的。

以Dan的demo为例子。文章地址

class ProfilePage extends React.Component {
  showMessage = () => {
    alert('Followed ' + this.props.user);
  };
  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };
  render() {
    return <button onClick={this.handleClick}>Follow</button>;
  }
}

这个组件的意思就是当你点击Follow的时候在三秒后输出当前你关注的这个人,也就是代码中对应的this.props.user。但是类式组件有一个问题,那就是假如你在点击这个按钮后的三秒内将传入的props改变,那么最后弹出的就不是Dan,而是Sophie。

bug.gif

类组件上的props是不可变的,但是this是可变的,this的数据可以修改。this.props调用时会获取最新的props,这是React保证数据实时性的手段。多数情况下,this.props和this.state的变化能够和预期中的渲染动作保持一致。但是在这个demo中,用setTimeout将渲染推迟了3s,打破这之中的关联,因此导致渲染时捕获到的不是我们想要的结果。

这同样也代表类式组件并没有把state和渲染紧紧绑定在一起。

而如果改造成函数式组件呢?

function ProfilePage(props) {
  const showMessage = () => {
    alert('Followed ' + props.user);
  };
  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };
  return (
    <button onClick={handleClick}>Follow</button>
  );
}

此时我们可以确保任何时机下获取的props都是触发函数时的那个props,这样我们保证了渲染结果符合预期。也就是说函数式组件真正的把数据和渲染绑定到了一起。