ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

为什么 setState 是异步的

2022-03-19 11:03:34  阅读:183  来源: 互联网

标签:count 异步 里面 函数 render 为什么 state setState


答案:

  1. 减少dom更新
  2. 副作用函数

认识的初级阶段

要回答这个问题,我们可以先罗列几个现象。

比方说,你有一个 button,你给这个 button 绑定了一个 onclick,在这个 onclick 里面你调用了一个 setState,在这个 onclick 没有执行完毕之前,你改的 state 是不会真的被更新的。同时,当 onclick 没有执行完毕,render 也不会被触发。

再比方说,你的父组件传了一个 callback,目的是把父组件的 state 改变一下,callback 里面有 setState,当这个 callback 没有执行完毕前,这个 callback 里面的 state 也是不会更改的。

但是,setState 在一些场合是同步的,比如你给原生 dom 添加事件处理函数的时候,调用了 setState,调用完后,setState 是立即被执行的。

setState 改变了状态并触发了 render, 而 render 往往是伴随着重绘和回流的,显然,这是非常影响浏览器性能的操作。如果设计成同步的话,试想,假使多个组件绑定了一个合成事件处理函数,那么,当这个事件函数执行的时候,setState 会多次修改 state 并 render。我们不如在 setState 的时候先不触发,而是先把那些需要更改的组件标记一下,最后一起改变 state 并渲染,这对浏览器性能的提升显然是有积极的影响的。

现在,请把我上面讲的内容都忘掉,因为,那只是我在初始阶段的肤浅认识而已。

认识的中级阶段

这里我要补一个面试题里面常考的例子:

import React, { Component } from 'react';
class App extends Component {
    constructor(props) {
        super(props);
        this.state = { count:0 }
    }
    increase=()=>{
        this.setState({count:this.state.count+1});
        console.log(this.state.count);
        this.setState({count:this.state.count+1});
        console.log(this.state.count);
        setTimeout(()=>{
            this.setState({count:this.state.count+1});
            console.log(this.state.count);
            this.setState({count:this.state.count+1});
            console.log(this.state.count);
        })
    }
    render() { 
        return ( 
            <div>
                <div>setState</div>
                <button onClick={this.increase}>btn</button>
            </div>
         );
    }
}

输出结果是

0,0,2,3

我们肯定有两个疑惑,第一个疑惑是,最前面两个 setState count + 1 以后,为什么输出结果还是 0,第二个疑惑是,为什么 setTimeout 里面,第一个输出不是 3,毕竟不是已经加了三次吗?

其实整个过程是这样的。

onClick 是合成事件,其对应的函数 increase 中的 setState 会被放到 batch Update 的 queue 中做统一的更新,而且,当 state 中的属性名称相同时,后一次的 setState 会把上一次队列中的覆盖掉。但是,异步任务中的 setState 并不会被放到 batch Update 的 queue 里面,所以那里面的 setState 是同步的。

于是,整个过程是这样的。

  1. 第一个 setState 放到 batchUpdateQueue 里。输出两个 count都是 0
  2. 第二个 setState 即将放到 queue 里面时,看到里面已经有一个 key = count 的 setState 了,于是,把那个 setState 替换掉。
  3. setTimeout 整个被放到事件循环队列的宏任务队列里面
  4. 合成事件函数结束
  5. batchUpdateQueue 批量执行 setState,count 此时为 1,因为 queue 里面只有一个 setState({count:this.state.count+1})。
  6. count 此时被更新为 1
  7. 宏任务执行,同步执行 setState。
  8. 输出 2,3

至于说 setState 为什么被设置为异步的,这是因为 react 的设计者想给那些不完全合格的设计者加一个强限制,假如说 setState 是同步的,那么每次 setState 都会调用 diff 算法去更新虚拟 dom。一个不合格的设计者在一个合成事件函数里面多次调用 setState,假如他被设计成同步的,一个合成事件函数被执行的时候,界面就会因为频繁操作虚拟 dom 而卡死。

内容装载来之:【前端面试】为什么 setState 是异步的 - 知乎

标签:count,异步,里面,函数,render,为什么,state,setState
来源: https://blog.csdn.net/u014071104/article/details/123590449

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有