美文网首页
React 现在为什么更推荐用函数式组件

React 现在为什么更推荐用函数式组件

作者: 弱冠而不立 | 来源:发表于2021-01-12 11:59 被阅读0次

    参考的原文章:函数式组件与类组件有何不同?
    开门见山:函数式组件获取了render时所需要的值。

    React的设计理念

    那我们如何理解这句话?

    举例说明

    点击这个链接查看例子:通过类组件去关注时,然后在延时的过程中去切换用户,就会发现关注的目标用户错乱了


    简化上面的链接的代码,有如下一个类组件:

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

    以及这样一个函数式组件

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

    这两种组件的方式,本意上都是点击一个按钮去关注某个用户,然后用setTimeOut去模拟网络请求提示结果到达异步的一个效果。
    点击查看上面链接的用例,尝试按照以下顺序来分别使用这两个按钮:

    1. 点击 其中某一个 Follow 按钮。
    2. 在3秒内 切换 选中的账号。
    3. 查看 弹出的文本。
    然后你就会发现,当你用类组件的的点击按钮去处理时,在这样一个异步等待结果的时候,去切换用户,然后alert出来的信息其实是错乱的。
    产生这样错误原因是因为什么呢?

    来看看类组件中 showMessage 的方法

      showMessage = () => {
        alert('Followed ' + this.props.user);
      };
    

    这个类方法从 this.props.user 中读取数据。
    在 React 中 Props 是不可变,props作为单向数据流,它只能由父组件流向子组件,这里不可变的意思就是,在一个确定的状态下,这个props是永远不变的。
    然而 this 是可变的!实际上这就是类组件中 this 的意义。因为组件是可复用的,所以类组件中的 this 就是以便你能在渲染方法或者生命周期中得到不同的实例(也可以说是最新的实例)。
    所以,当我们模拟异步请求的时候,我们又进行了切换操作,使得组件进行了重新渲染,this 就改变了,此时获取的 props 也是最新的。

    从React的设计理念上来说,UI 在概念上就是当前应用状态的一个渲染函数,我们的事件处理程序(render) 本质上就是一个拥有特定 props 和 state 的特定渲染。但是,我们的 showMessage 回调并没有与任何一个特定的渲染“绑定”在一起,所以它“失去”了正确的 props。从 this 中读取数据的这种行为,切断了这种联系。

    假如函数式组件不存在。我们将如何解决这个问题?

    从问题的本质出发,因为异步等待的过程中然后切换用户,导致我们的 this 改变。

    1. 在回调调用之前就读取 this.props,然后保存下来。然后通过参数传递的方式,传递到回调函数中。
      showMessage = (user) => {
        alert('Followed ' + user);
      };
    
      handleClick = () => {
        const {user} = this.props;
        setTimeout(() => this.showMessage(user), 3000);
      };
    

    虽然能起作用,但是这种方法使得代码明显变得更加冗长,并且随着时间推移容易出错。如果我们需要的不止是一个props怎么办?如果我们还需要访问state怎么办?...

    1. 利用 JS 的闭包
      简述一下闭包:因为JS的函数作用域是在声明时就确定了的,所以函数作用域内部的变量,不会受到外部的影响而销毁。只有当前函数执行完毕,才会释放整个作用域。
      通常情况下,会避免使用闭包,因为会有内存泄漏,变量随时间推移而变化...等问题。但正也是因为React中,props和state是不可变的。这就消除了闭包的一个主要缺陷。
    class ProfilePage extends React.Component {
      render() {
        // 你在渲染的时候就已经“捕获”了props:
        const props = this.props;
    
        // Note: we are *inside render*.
        // These aren't class methods.
        const showMessage = () => {
          alert('Followed ' + props.user);
        };
    
        const handleClick = () => {
          setTimeout(showMessage, 3000);
        };
    
        return <button onClick={handleClick}>Follow</button>;
      }
    }
    

    嗯,上面的例子很正确,就是看起来很奇怪。我们在render方法中定义各种函数,而不是使用class的方法,那么使用类的意义在哪里?所以这里我们完全可以使用函数式组件了嘛。

    通过删除类的“包裹”来简化代码:
    function ProfilePage(props) {
      const showMessage = () => {
        alert('Followed ' + props.user);
      };
    
      const handleClick = () => {
        setTimeout(showMessage, 3000);
      };
    
      return (
        <button onClick={handleClick}>Follow</button>
      );
    }
    

    就像上面这样,props 仍旧被捕获了 —— React将它们作为参数传递。不同于 this,props 对象本身永远不会被 React 改变。

    函数式版本中,点击关注Sophie的账号,然后改变选择为Sunil仍旧会弹出'Followed Sophie'

    相关文章

      网友评论

          本文标题:React 现在为什么更推荐用函数式组件

          本文链接:https://www.haomeiwen.com/subject/rmssaktx.html