美文网首页
setState 简单整理

setState 简单整理

作者: Scaukk | 来源:发表于2018-05-05 13:43 被阅读138次

好久没写东西了。。。。
来头条之后, 每天身体被掏空。也没多少时间写东西,
今天周末,上午没啥事, 简单写写,


一个例子

假如有这样一个点击执行累加场景:

// ...
  this.state = {
    count: 0,
  }

  incrementCount() {
    this.setState({count: this.state.count + 1});
  }

  handleIncrement = () => {
    this.incrementCount();
    this.incrementCount();
    this.incrementCount();
  }


 <button ref="button" onClick={this.handleIncrement}>点击</button>
// ...

每一次点击, 会执行三次累加,看一下输入:


image.png

并没有达到预期的效果,纠正也很简单:

incrementCount() {
  this.setState((prevState) => {
    return {count: prevState.count + 1}
  });
}

再看输出:


image.png

setState 的时候, 一个传入了object, 一个传入了更新函数。
区别在于: 传入一个更新函数,就可以访问当前状态值。 setState调用是批量处理的,因此可以让更新建立在彼此之上,避免冲突。

那问题来了, 为什么前一种方式就不行呢? 具体一点说, setState为什么不会同步更新组件状态呢? 带着这个疑问,继续往下看。

进入这个问题之前,我们先回顾一下现在对setState的认知:

  1. setState不会立刻改变React组件中state的值.
  2. setState通过触发一次组件的更新来引发重绘.

重绘指的就是引起React的更新生命周期函数4个函数:

  • shouldComponentUpdate(被调用时this.state没有更新;如果返回了false,生命周期被中断,虽然不调用之后的函数了,但是state仍然会被更新)
  • componentWillUpdate(被调用时this.state没有更新)
  • render(被调用时this.state得到更新)
  • componentDidUpdate
  1. 多次setState函数调用产生的效果会合并。

如果每一次setState调用都走一圈生命周期,光是想一想也会觉得会带来性能的问题,其实这四个函数都是纯函数,性能应该还好,但是render函数返回的结果会拿去做Virtual DOM比较和更新DOM树,这个就比较费时间。

目前React会将setState的效果放在队列中,积攒着一次引发更新过程,为的就是把Virtual DOM和DOM树操作降到最小,用于提高性能。

查阅一些资料后发现,某些操作还是可以同步更新this.state的。
直接说结论吧:

在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state。

所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

https://jsbin.com/mavolejufi/edit?html,js,console,output

盗用一张图:

setState 过程

在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中。
而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

知道上面的一些理论之后, 我们再看一个例子就很清晰了:

class Example extends React.Component {
  constructor() {
    super();
    this.state = {
      val: 0
    };
  }
  
  componentDidMount() {
    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    // 第 1 次 log

    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    // 第 2 次 log

    setTimeout(() => {
      this.setState({val: this.state.val + 1});
      console.log(this.state.val);  // 第 3 次 log

      this.setState({val: this.state.val + 1});
      console.log(this.state.val);  // 第 4 次 log
    }, 0);
  }

  render() {
    return null;
  }
};

毫无疑问输出 0 0 2 3 ;

前两次在isBatchingUpdates 中,不用更新state, 输出两个0。
后面两次会同步更新, 分别输出2, 3;

上面的例子,我们就知道了setState 是可以同步更新的,但是还是尽量避免直接使用, 仅作了解用。
如果你非要玩一些骚操作,写出这样的代码去直接去操作this.state:

    this.state.count = this.state.count + 1;
    this.state.count = this.state.count + 1;
    this.state.count = this.state.count + 1;
    this.setState();

我只能说, 大胸弟, 你很骚。吾有旧友叼似汝,而今坟草丈许高。

根据以上内容, 简单重复下结论:

  • 不要直接去操作this.state, 这样会造成不必要的性能更问题和隐患。
  • 由React引发的事件处理,调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state。

就简单写到这吧, 要出门了 :)。

扩展阅读:
https://reactjs.org/docs/faq-state.html#what-does-setstate-do

关于事务,还有相关源码的问题可以参考:
https://zhuanlan.zhihu.com/p/20328570

https://zhuanlan.zhihu.com/p/25882602
https://zhuanlan.zhihu.com/p/26069727
https://zhuanlan.zhihu.com/p/25990883
https://reactjs.org/docs/faq-state.html#what-does-setstate-do
https://reactjs.org/docs/react-component.html#setstate

相关文章

  • setState 简单整理

    好久没写东西了。。。。来头条之后, 每天身体被掏空。也没多少时间写东西,今天周末,上午没啥事, 简单写写, 一个例...

  • react setState

    因为 setState在react中非常重要,所以单独拎出来整理它的要点 什么是setState? react是通...

  • React setState 整理总结

    先看一个例子 假如有这样一个点击执行累加场景: 每一次点击, 累加三次,看一下输入: 并没有达到预期的效果,纠正也...

  • react拓展

    setState() setState更新状态的2种方式 对象式的setState 函数式的setState 对象...

  • setState()状态更新函数

    理解setState的关键 setState不会立刻改变React组件中state的值; setState通过引发...

  • react native 子组件传值给父组件

    简单粗暴上代码 父组件 子组件 如果没有加bind(this)会报错-this.setState is not a...

  • 08react基础-react原理

    setState()更新数据 setState()更新数据是异步的 注意:使用该语法,后面的setState不要依...

  • 『react』setState()特性

    一.setState()更新数据 由于setState()更新数据是异步的,所以后面的setState()不要依赖...

  • setState相关

    - setState相关 setState是同步执行的,但是state不一定同步更新 多次执行setState,...

  • react 中的 API

    设置状态:setState setState(object nextState[,function callbac...

网友评论

      本文标题:setState 简单整理

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