前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解react的setState

深入理解react的setState

作者头像
yuezhongbao
发布2019-03-13 15:31:20
8990
发布2019-03-13 15:31:20
举报
文章被收录于专栏:前端实习日记前端实习日记

1.组件挂载图

  • 了解生命周期函数的执行顺序
图片描述
图片描述

2.生命周期执行顺序

尝试一下

  • 可以看到在组件在组件初始化时,只执行如下三个方法:
图片描述
图片描述
  • 在父组件状态改变时,依次执行的生命周期函数是:
图片描述
图片描述
  • 我试着分别在这几个生命周期函数中setState了一下,发现在componentWillUpdate、render、componentDidUpdate 中会报错,也就是说在componentWillUpdate、render、componentDidUpdate中不可以setState。

1.那么问题来了这些周期方法为什么不可以setState? 2.setState异步机制,怎么处理,setState(函数)

代码语言:javascript
复制
componentDidMount() {
    SynapseAnalytics.init({ type:Enum.pageTypeEnum.otherPage });
    this.setState({
        val:this.state.val + 1
    });
    //第一次输出  0
    console.log(this.state.val);
    this.setState({
        val:this.state.val + 1
    });
    //第二次输出 0
    console.log(this.state.val);
    setTimeout(()=>{
        this.setState({val:this.state.val + 1});
        //第三次输出 2
        console.log(this.state.val);
        this.setState({
            val:this.state.val + 1
        });
        //第四次输出 3
        console.log(this.state.val);
    }, 0);
} 
  • 依次输出0、0、2、3;因为react并不是setState之后state的值就会改变的,若是这样就太消耗内存了,失去了setState存在的意义。
  • 这里存在一个setstate调用栈的问题,问题来了setState之后都发生了什么
  • 1.this.setState(newState) =>
  • 2.newState存入pending队列 =>
  • 3.调用enqueueUpdate =>
  • 4.是否处于批量更新模式 => 是的话将组件保存到dirtyComponents
  • 5.不是的话遍历dirtyComponents,调用updateComponent,更新pending state or props
  • enqueueUpdate的源码如下:
代码语言:javascript
复制
 function enqueueUpdate(component){
       //injected注入的
       ensureInjected();
       //如果不处于批量更新模式
       if(!batchingStrategy.isBatchingUpdates){
           batchingStrategy.batchedUpdates(enqueueUpdate, component);
           return;
       }
       //如果处于批量更新模式
       dirtyComponents.push(component);
   } 
  • 如果isBatchingUpdates为true,则对所有队列中的更新执行batchedUpdates方法,否则只把当前组件(即调用了setState的组件)放入dirtyComponents数组中,例子中4次setState调用的表现之所以不同,这里的逻辑判断起了关键作用。

参考链接 参考链接

  • 连续调用了多次setState,但是只引发了一次更新生命周期,因为React会将多个this.setState产生的修改放在一个队列里,缓一缓,攒在一起,觉得差不多了在引发一次更新过程。

所以攒的过程中如果你不停的set同一个state的值,只会触发最后一次,例如上面那道题

  • 那么问题又来了:我就想让第三次输出为3,别给我覆盖掉该怎么办?

其实setState还有一个用法,它不止可以接受对象作为参数,还可以接受函数。

3.函数式的setState的用法

直接看代码:

代码语言:javascript
复制
componentDidMount(){
    SynapseAnalytics.init({type:Enum.pageTypeEnum.otherPage});
    this.setState(this.fn.bind(this));
    //第一次输出
    console.log(this.state.val);
    this.setState(this.fn.bind(this));
    //第二次输出
    console.log(this.state.val);
    setTimeout(()=>{
        this.setState({val:this.state.val+1});
        //第三次输出
        console.log(this.state.val);
        this.setState({
            val:this.state.val+1
        });
        //第四次输出
        console.log(this.state.val);
    },0);
}
fn(state,props){
    return{
        val:state.val+1
    }
}
  • 这个函数可以接受两个参数,一个是当前state的值,一个是当前props,这个函数返回一个对象代表对state的修改。

我理解这个state其实就相当于一个全局变量,每次累加的不是this.state,而是state这个变量,所以无论累加多少次,最后将state这个变量赋值给this.state。

注意:在这累加的过程中,若你在函数式的setState方法后面又穿插使用了传统的对象式(this.setState({val:this.state.val + 1}))的话,之前累加的就全白费了,因为上面说过了this.state.val还是0,它只有在render之后才会改变。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.组件挂载图
  • 2.生命周期执行顺序
  • 3.函数式的setState的用法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档