We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
继上一章批量更新优化,我们得到了一个 updateQueue ,且以 first , next 形式将 update 对象链接起来。
updateQueue
first
next
update
updateQueue 挂载在具体的 instance 下,待遍历到该 instance 对应的 fiber 时,处理更新队列。
instance
fiber
在回调函数执行完后,需要 performWork ,将状态的改变应用到视图上。这样就进入了页面渲染流程,不过不一样的是这次不是第一次渲染了。
performWork
root
newState
update.next
assign
partialState
oldState
nextUpdate
setState
callback
updateQueue.callbackList
effectTag
commitRoot
if (workInProgress.updateQueue !== null) { newState = processUpdateQueue(current, workInProgress, workInProgress.updateQueue, instance, newProps, renderExpirationTime); } workInProgress.effectTag |= Callback
在改变state之后,执行生命周期函数 shouldComponentUpdate, componentWillUpdate, render。在 render 执行之后,改变了 children,故须将改变了的差异应用到视图上。这时便要对 children 进行 reconcileChildren(调和)
shouldComponentUpdate, componentWillUpdate, render
render
children
reconcileChildren
reconcileChildren 阶段将 nextChildren 和原先的 child 进行对比,可以选择重用原先的 childFiber ,并改变 pendingProps和memoizedProps。
nextChildren
child
childFiber
pendingProps
memoizedProps
之后,在 completeWork 的时候对新旧 props 进行 diff ,并将 workInProgress.updateQueue 置为最新 updatePayload( key 为2n,value 为2n+1) ,并改变 workInProgress.effectTag |= Update
completeWork
props
diff
workInProgress.updateQueue
updatePayload
key
value
workInProgress.effectTag |= Update
for (var i = 0; i < updatePayload.length; i += 2) { var propKey = updatePayload[i]; var propValue = updatePayload[i + 1]; }
workInProgress.effectTag
commit
commitAllHostEffects 阶段,将拿到更新后的 fiber - finishedWork 。在将 finishedWork 下面的 effect 串,按序应用,改变视图。
commitAllHostEffects
finishedWork
effect
对每个 effectFiber 的 effectTag 进行位运算处理,得到 primaryEffectTag , primaryEffectTag 代表三种操作:插入、更新、插入并更新、删除
effectFiber
primaryEffectTag
var primaryEffectTag = effectTag & ~(Callback | Err | ContentReset | Ref | PerformedWork);
利用 return 属性,找到 parentFiber。
return
parentFiber
getHostSibling,是为了找到在哪个 fiber 对应的 dom 元素前插入目前 fiber 对应的 dom。这个元素是目前 fiber 之后 effectTag 不为 Placement 或 PlacementAndUpdate 的 fiber 对应的 dom 元素
getHostSibling
dom
Placement
PlacementAndUpdate
function commitPlacement () { var parentFiber = getHostParentFiber(finishedWork); var before = getHostSibling(finishedWork); } function getHostParentFiber(fiber) { var parent = fiber['return']; while (parent !== null) { if (isHostParent(parent)) { return parent; } parent = parent['return']; } } function getHostSibling(fiber) { var node = fiber; siblings: while (true) { while (node.sibling === null) { // 如果父级是HostComponent,返回null if (node['return'] === null || isHostParent(node['return'])) { return null; } node = node['return']; } node.sibling['return'] = node['return']; node = node.sibling; // 直接看fiber.sibling while (node.tag !== HostComponent && node.tag !== HostText) { if (node.effectTag & Placement) { continue siblings; } if (node.child === null || node.tag === HostPortal) { continue siblings; } else { node.child['return'] = node; node = node.child; } } // 如果fiber的effectTag为Placement或者PlacementAndUpdate if (!(node.effectTag & Placement)) { return node.stateNode; } } }
在得到 parentFiber 和 before 后,就能实行具体的节点插入措施,分别为 insertBefore ,appendChild 措施
before
insertBefore
appendChild
更新操作发生在 commitWork 中,由于更新操作在 diffProperties 算法中讲过,当重用 dom ,但是某些属性发生改变时需要更新,更新的内容以键值对形式 push 进 updatePayload ,并挂载 fiber.updateQueue 上,得到 updatePayload,接着就需要 commitUpdate
commitWork
diffProperties
push
fiber.updateQueue
commitUpdate
function commitUpdate () { updateFiberProps(); // 将新的props挂载到 `dom` 下 updateProperties(); }
在 updateDOMProperties$1 函数中更新 dom 时
updateDOMProperties$1
对 style 的设置用驼峰命名,但 html 中的 style 属性用'-'分割
style
html
获取元素CSS值之getComputedStyle方法熟悉
先插入再更新
删除操作发生在 commitDeletion 中,卸载 dom 元素下面子组件,待组件卸载完后,删除 dom 节点,分离删除 fiber
commitDeletion
The text was updated successfully, but these errors were encountered:
No branches or pull requests
继上一章批量更新优化,我们得到了一个
updateQueue
,且以first
,next
形式将update
对象链接起来。updateQueue
挂载在具体的instance
下,待遍历到该instance
对应的fiber
时,处理更新队列。在回调函数执行完后,需要
performWork
,将状态的改变应用到视图上。这样就进入了页面渲染流程,不过不一样的是这次不是第一次渲染了。root
遍历到此instance
对应的fiber
时,会根据updateQueue
处理得到新的newState
。处理过程是从第一个update
对象开始,迭代循环update.next
,不停的使用assign
形式,将partialState
覆盖oldState
到newState
上,直到不再有nextUpdate
,然后返回newState
。此过程中还能收集setState
的回调函数,具体做法是将callback
添加至updateQueue.callbackList
队列,并设置effectTag
,以便在commitRoot
阶段触发。具体做法如下图所示:在改变state之后,执行生命周期函数
shouldComponentUpdate, componentWillUpdate, render
。在render
执行之后,改变了children
,故须将改变了的差异应用到视图上。这时便要对children
进行reconcileChildren
(调和)reconcileChildren
阶段将nextChildren
和原先的child
进行对比,可以选择重用原先的childFiber
,并改变pendingProps
和memoizedProps
。之后,在
completeWork
的时候对新旧props
进行diff
,并将workInProgress.updateQueue
置为最新updatePayload
(key
为2n,value
为2n+1) ,并改变workInProgress.effectTag |= Update
workInProgress.effectTag
来决定执行commit
操作如何根据更新了的fiber来改变视图
commitAllHostEffects
阶段,将拿到更新后的fiber
-finishedWork
。在将finishedWork
下面的effect
串,按序应用,改变视图。对每个
effectFiber
的effectTag
进行位运算处理,得到primaryEffectTag
,primaryEffectTag
代表三种操作:插入、更新、插入并更新、删除利用
return
属性,找到parentFiber
。getHostSibling
,是为了找到在哪个fiber
对应的dom
元素前插入目前fiber
对应的dom
。这个元素是目前fiber
之后effectTag
不为Placement
或PlacementAndUpdate
的fiber
对应的dom
元素在得到
parentFiber
和before
后,就能实行具体的节点插入措施,分别为insertBefore
,appendChild
措施更新操作发生在
commitWork
中,由于更新操作在diffProperties
算法中讲过,当重用dom
,但是某些属性发生改变时需要更新,更新的内容以键值对形式push
进updatePayload
,并挂载fiber.updateQueue
上,得到updatePayload
,接着就需要commitUpdate
在
updateDOMProperties$1
函数中更新dom
时对
style
的设置用驼峰命名,但html
中的style
属性用'-'分割获取元素CSS值之getComputedStyle方法熟悉
先插入再更新
删除操作发生在
commitDeletion
中,卸载dom
元素下面子组件,待组件卸载完后,删除dom
节点,分离删除fiber
The text was updated successfully, but these errors were encountered: