美文网首页React
react之setState的异步及合并执行更新组件

react之setState的异步及合并执行更新组件

作者: Mr无愧于心 | 来源:发表于2020-04-16 10:10 被阅读0次

前言须知

  1. jsx的渲染过程
    jsx会经过babel编译成createElement函数的结构,然后createElement执行产生虚拟dom结构VNode(就是一个有一定属性的对象结构),然后通过rander函数处理VNode为虚拟节点,在页面中渲染。详细请点击此处

  2. dom的更新过程
    diff算法对比新旧VNode,如果新旧VNode不一样就调用rander重新渲染视图的过程。详细请点击此处

回归正题

setState的使用
为了避免每执行一次 setState,就重新生成 newVNode 进行 diff。,会造成主进程的阻塞,页面的卡死,所以setState做了异步处理合并执行(多次连续调用会被最终合并成一次)的两种优化。
异步处理的实现可以通过promise来实现

  • setState的实现
let updateQueue=[];
function enqueueRender(updater) { 
    // 将所有 updater 同步推入更新队列中
    // 为实例添加一个属性 __dirty,标识是否处于待更新状态
    // 初始 和 更新完毕,该值会被置为 false
    // 推入队列时,标记为 true
    if (
        !updater.__dirty && 
        (updater.__dirty = true) && 
        updateQueue.push(updater) === 1//添加入队列
    ) {
        // 异步化冲洗队列(微任务)
        // 最终只执行一次冲洗
        // 合并一次循环中多次 updater
      new Promise().then(()=>{
        if (updateQueue.length) {
          updateQueue.sort()
          let curUpdater = updateQueue.pop()
          while (curUpdater) {
            if (curUpdater.__dirty) {
              // 当组件处于 待更新态 时,触发组件更新
              // 如果该组件已经被更新完毕,则该状态为 false
              // 则后续的更新均不再执行
              curUpdater.__update()//更新组件  在组件更新完毕设置this.__dirty = false
              //处理callback回调函数
              const callbacks = curUpdater.__setStateCallbacks
              let cbk
              if (callbacks && callbacks.length) {
                while (cbk = callbacks.shift()) cbk.call(curUpdater)
              }   
            }
            curUpdater = updateQueue.pop()
          }
      })
   }
}

setState(partialState = {}, callback?) {
  if (typeof partialState === 'function') {
    partialState = partialState(this.state, this.props)
  }
        
  this.__nextState = {
    ...this.state,
    ...partialState,
  }
    // 缓存回调
  callback && this.__setStateCallbacks.push(callback)
  // 把组件自身先推入更新队列
  enqueueUpdate(this)
}
  • __update更新组件
    diff虚拟DOM
    重新渲染组件
__update(){
  diff(oldVNode, newVNode);
  render();
}
function diff(oldVNode, newVNode) {
    if (isSameVNode(oldVNode, newVNode)) {
        if (typeof oldVNode.type === 'function') {
            // 组件节点
            diffComponent(oldVNode, newVNode)
        } else {
            // 元素节点,
            // 直接执行比对
            diffVNode(oldVNode, newVNode)
        }
    } else {
        // 新节点替换旧节点
        ...
    }
}

// 组件比对
function diffComponent(oldCompVNode, newCompVNode) {
    const { instance, vnode: oldVNode, elm } = oldCompVNode
    const { props: nextProps } = newCompVNode
    if (instance && oldVNode) {
        instance.__dirty = false
        // 更新状态和属性
        instance.__nextProps = nextProps
        if (!instance.__nextState) instance.__nextState = instance.state        
        // 复用旧组件实例和元素
        newCompVNode.instance = instance
        newCompVNode.elm = elm
        // 使用新属性、新状态,旧组件实例
        // 重新生成 新虚拟DOM
        const newVNode = initComponent(newCompVNode)       
        // 递归触发 diff
        diff(oldVNode, newVNode)
    }
}

由于更新队列为异步的,因此当多次连续调用 setState 时,组件的状态会被 同步合并,待全部完成后,才会进入更新队列的冲洗并最终只执行一次组件更新


本文参考:https://juejin.im/post/5e65a258f265da57133b37cc#heading-7

相关文章

  • react之setState的异步及合并执行更新组件

    前言须知 jsx的渲染过程jsx会经过babel编译成createElement函数的结构,然后createEle...

  • React的异步更新的setState

    React的异步更新的setState 为何说setState方法是异步的? React Native 开发小Ti...

  • react的旧的生命周期

    注意:State 的更新可能是异步的,React 可能会把多个 setState() 调用合并成一个调用

  • 正确使用setState

    1、参数 用于产生与当前state合并的子集 state更新后立即执行的回调函数 2、setState更新(异步更...

  • 2018-12-10

    1.状态更新可能是异步的 React 可以将多个setState()调用合并成一个调用来提高性能。 因为this....

  • react的setState原理

    react的setState批量更新与vue有很大差别,vue是利用异步函数batch执行所有更改的state,而...

  • react使用问题集

    setState是浅合并 关于react组件无法获取history属性的问题 withRouter高阶组件,提供了...

  • React不熟悉地方的笔记

    1. 状态更新可能是异步的 React 可以将多个setState() 调用合并成一个调用来提高性能。因为 thi...

  • 解决react-native中setState同步更新

    setState 同步更新 为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序...

  • React_setState

    setState : 修改组件内变量。 优点 可以对更新进行优化。(异步更新)setState会将大批量的更新进行...

网友评论

    本文标题:react之setState的异步及合并执行更新组件

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