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

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

React的设计理念

那我们如何理解这句话?

举例说明

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


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

class ProfilePage extends React.Component {
  showMessage = () => {
    alert('Followed ' + this.props.user);
  };

  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };

  render() {
    return ;
  }
}

以及这样一个函数式组件

function ProfilePage(props) {
  const showMessage = () => {
    alert('Followed ' + props.user);
  };

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };

  return (
    
  );
}

这两种组件的方式,本意上都是点击一个按钮去关注某个用户,然后用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 ;
  }
}

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

通过删除类的“包裹”来简化代码:
function ProfilePage(props) {
  const showMessage = () => {
    alert('Followed ' + props.user);
  };

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };

  return (
    
  );
}

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

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

你可能感兴趣的:(React 现在为什么更推荐用函数式组件)