UNDERCOVERj / tech-blog

个人博客☺️
39 stars 1 forks source link

React16.2源码解析-diffProperties算法 #17

Open UNDERCOVERj opened 6 years ago

UNDERCOVERj commented 6 years ago

reconciliation 生成一系列 child fibers 后,会进入 completeUnitOfWork 阶段。如果 workInProgress 对应的 fiber 是需要更新的 HostComponent (请注意,不是说的第一次渲染页面,判断逻辑如下)

workInProgress.alternate !== null && workInProgress.stateNode != null

那么需要对 props 进行 diff 区分,如果有不一样的键值对,则加入到 updatePayload 数组中,并挂载到 workInProgress.updateQueue

具体diff函数:diffProperties$1

新旧 props 分别为:lastPropsnextProps ,如果 lastProps[propKey] === nextProps[propKey] 则跳过

对比 lastProps.stylenextProps.style

  1. 都是对象
propKey lastProps.style nextProps.style styleUpdates
top 10px 20px 20px
left 20px undefined ''

(updatePayload = updatePayload || []).push('style', {top: '20px', left: ''})

  1. lastProps.style 没有定义

(updatePayload = updatePayload || []).push('style', nextProps.style)

children 为文本(stringnumber )且有变化时

(updatePayload = updatePayload || []).push('children', '' + nextProps.children)

如果nextProps.propKey有值,在 document 上绑定 eventName 函数,确保能触发 dispatchEvent 回调函数。如果新旧props的props[eventName]不一样,则:

updatePayload = [];

diff完后

diff 完有差异,updatePayload 就为数组,否则,updatePayloadnull

updatePayload 返回后,在 updateHostComponent 中,将 updatePayload 挂载在 workInProgress.updateQueue 上,并且 updatePayload 不为 null ,则将 workInProgress 标志为更新

workInProgress.updateQueue = updatePayload;
if (updatePayload) {
    // 这会把Placement变为UpdateAndPlacement
    workInProgress.effectTag |= Update;
}

在最后的 commitWork 阶段,才根据 effectTag 来执行视图的更新

diff的作用

  1. 检查是否有 dom 属性更新(体现在 props 中)
  2. 若有不同,需要标记更新,并提供 updatePayload,供 commitWork 阶段使用
YeziZhao commented 6 years ago

目前已经将作者写的基本消化完了,很感谢你的总结,按照你的思路进行学习很好!辛苦了!

UNDERCOVERj commented 6 years ago

@yeziTesting 加油