react的setState的执行机制

介绍

react 中组件本身的状态是通过 state 来维护的,但是 state 不能直接进行修改,必须使用 setState 方法,将修改的 state 和原来的 state 进行比较,组成一个新的 state

使用

constructor(props) {
    super(props);
    this.state = {
        value: 1
    }
}
componentDidMount() {
    this.setState({
        value: 2 // 这样value就会变成2
    })
}

此时我想在同个作用域下用这个 value 了,但是获取不到?

componentDidMount() {
    this.setState({
        value: 2
    })
    console.log(this.state.value)
}

结果输出的还是 1,我明明已经改变它了,可是我却取不到,尚且先认为 setState 是一个异步操作,输出语句作为同步代码先执行了(js 先执行完同步代码再调取异步队列)
那么此刻我该如何解决?
解决方式(待补充):

  • async/await
async componentDidMount() {
    await this.setState({
        value: 2
    })
    console.log(this.state.value)
}
  • setState 的第二个参数是个回调函数,可以利用它来获取
componentDidMount() {
    this.setState({
        value: 2
    }, () => {console.log(this.state.value)})
}

如果在 componentDidMount 使用多个会如何?

componentDidMount() {
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
}

结果竟然输出了 2,你哪怕是异步,也不能这么玩啊,那么问题在哪?
首先了解到,setState 会将钩子函数中的 state 进行合并操作,先将每一个 setState 加入一个 state 状态维护的队列,最终组成一个 state,然后进行渲染,那么以上两个相同的 setState 就会被合并成一个,所以只是进行了一个 setState 操作
为何要采取这种合并的方式
因为 state 一变就会触发组件的重新渲染,合并能够减少渲染的次数,起到了提高性能的作用

setState 真的是异步操作吗?

首先 setState 本身不是异步代码写的,这是可以确认的,但是一遇到 setState,他就会被放到状态队列,等待被合并,所以此时它不能立即获取到新的 state,所以可以认为是一个”异步“,但它也可能是同步的

componentDidMount() {
        setTimeout(() => {
            this.setState({
                value: this.state.value + 1
            })
            this.setState({
                value: this.state.value + 1
            })
            console.log(this.state.value)
        })
}

以上的代码输出了 3,就因为多加了一个 setTimeout 定时器?
setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout中都是同步的

再来深入

  • enqueueUpdate
    setState 最终是通过 enqueueUpdate 函数执行 state 更新
function enqueueUpdate(component) {
  ensureInjected();
  // 不需要合并更新(直接同步更新)
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  // 合并更新(放到状态队列合并)
  dirtyComponents.push(component);
}
  • isBatchingUpdates
    该变量是取决是否进行合并更新,true 就是进行合并更新,false 就是不进行
    在进入钩子函数前,该变量初始值为 true,当前置钩子的合并更新(包括没有进行更新操作)完成,该值就会变成 false,所以在 setTimeout 中是同步执行,不会进行合并操作

总结:

  • setState在钩子函数中是”异步”操作,需要等待合并,才能取到结果
  • setState在原生事件和 setTimeout中都是同步的,可以直接取到结果
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值