setState
setState是我们常用的更改状态的方法,state的改变标示者组件要更新。但调用setState是否就触发组件更新呢?
class App extends Component {state={count: 0}batchUpdates = () => {this.setState({count: this.state.count + 1})}render() {return (<div onClick={this.batchUpdates}>{`点击更改状态${ this.state.count }`} </div>)}}ReactDOM.render(<App/>, document.getElementById('root'));
inst为App的实例,值为:
事件调用此处不再叙述,执行事件方法时,this.setState会调用 Component.prototype.setState。
Component.prototype.setState = function (partialState, callback) {this.updater.enqueueSetState(this, partialState, callback, 'setState');};var classComponentUpdater = {//...enqueueSetState: function enqueueSetState(inst, payload, callback) {var fiber = get(inst);var currentTime = requestCurrentTime();var expirationTime = computeExpirationForFiber(currentTime, fiber);var update = createUpdate(expirationTime);update.payload = payload;if (callback !== undefined && callback !== null) {update.callback = callback;}flushPassiveEffects();enqueueUpdate(fiber, update);scheduleWork(fiber, expirationTime);}//....}
payload 为 setState 中的 partialState,此处的值为{ count: 1 };callback 为undefined;
enqueueUpdate
createUpdate(expirationTime) 和 update.payload = payload 会生成 update对象,值为:
flushPassiveEffects 用来刷新 优先级低 的effects。
初创的fiber没有 updateQueue ,当调用enqueueUpdate 会创建更新队列。执行代码如下:
function enqueueUpdate(fiber, update) {// Update queues are created lazily.var alternate = fiber.alternate;// alternate 为nullvar queue1 = void 0;var queue2 = void 0;if (alternate === null) {// There's only one fiber.queue1 = fiber.updateQueue;queue2 = null;if (queue1 === null) {//fiber.memoizedState 的值为 { count: 0 },之前的值queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);}} else { //... }if (queue2 === null || queue1 === queue2) {appendUpdateToQueue(queue1, update);} else { //... }}function createUpdateQueue(baseState) {var queue = {baseState: baseState,firstUpdate: null,lastUpdate: null,firstCapturedUpdate: null,lastCapturedUpdate: null,firstEffect: null,lastEffect: null,firstCapturedEffect: null,lastCapturedEffect: null};return queue;}function appendUpdateToQueue(queue, update) {// Append the update to the end of the list.if (queue.lastUpdate === null) {// Queue is emptyqueue.firstUpdate = queue.lastUpdate = update;} else {queue.lastUpdate.next = update;queue.lastUpdate = update;}}
createUpdateQueue 创建的队列值为:
执行完appendUpdateToQueue 后,得到的query的值为:
当前 fiber为type 为 ƒ App(),此时的队列的值保存在 fiber.updateQueue。
scheduleWork
scheduleWork 可参考 updateContainer 中scheduleWork。与updateContainer不同,在调用requestWork时,由于isBatchingUpdates 为true,直接返回没有执行到 performSyncWork。
function requestWork(root, expirationTime) {addRootToSchedule(root, expirationTime);if (isRendering) {return;}if (isBatchingUpdates) {// isBatchingUpdates为trueif (isUnbatchingUpdates) {nextFlushedRoot = root;nextFlushedExpirationTime = Sync;performWorkOnRoot(root, Sync, false);}return;//直接返回}if (expirationTime === Sync) {performSyncWork();} else {scheduleCallbackWithExpirationTime(root, expirationTime);}}
此处有一个关键点是 addRootToSchedule,将 root 添加到 schedule 中,root只添加一次。addRootToSchedule在render中介绍过,传送门。
多次调用setState
class App extends Component {state = { val: 0 }batchUpdates = () => {this.setState({ val: this.state.val + 1 });console.log(this.state.val);this.setState({ val: this.state.val + 1 });console.log(this.state.val);this.setState({ val: this.state.val + 1 });console.log(this.state.val);}render() {return (<div onClick={this.batchUpdates}>{`Counter is ${this.state.val}`} </div>)}}
每调执行 this.setState 就调用 classComponentUpdater.enqueueSetState方法,生成 fiber.updateQueue队列。当执行完 batchUpdates 方法时,得到两个fiber的updateQueue为:

执行完 batchUpdates 方法时state并没有更新,只创建了队列。此时 queue 的 payload 都为{ val: 1 }。
队列值的变更
多次调用setState和 单次调用setState 是相似的,此处以单次作为示例说明,队列的执行不再赘述。
在 updateClassInstance -> processUpdateQueue 中会将 workInProgress 队列中的 firstUpdate、lastUpdate 设置为null,此时 workInProgress.updateQueue 为:
但此时 workInProgress.alternate.updateQueue 中还是有队列的,值为:
更新完成后,若再次更改state,在 enqueueUpdate 创建队列queue1 、queue2时,一个是只有更新队列,一个是 next 指向更新队列。然后进入更新。
在更新的过程中,进入 createWorkInProgress 中会设置 workInProgress.updateQueue = current.updateQueue 。这样就使 workInProgress.updateQueue的队列(带next的队列)被遗弃,直接使用current.updateQueue。这个涉及 dom与fiber 和 current 与 workInProgress 交换,具体请参考 performWork 。
更新
更新setState 通常要使用派发事件并调用interactiveUpdates$1(事件派发中的)。
function interactiveUpdates$1(fn, a, b) {if (!isBatchingUpdates && !isRendering &&lowestPriorityPendingInteractiveExpirationTime !== NoWork) {// Synchronously flush pending interactive updates.performWork(lowestPriorityPendingInteractiveExpirationTime, false);lowestPriorityPendingInteractiveExpirationTime = NoWork;}var previousIsBatchingUpdates = isBatchingUpdates;isBatchingUpdates = true;try {// 执行事件的方法return scheduler.unstable_runWithPriority(scheduler.unstable_UserBlockingPriority,function () { return fn(a, b); });} finally {isBatchingUpdates = previousIsBatchingUpdates;if (!isBatchingUpdates && !isRendering) {performSyncWork();}}}
在 scheduler.unstable_runWithPriority 执行完事件后,就进入到 finally 中,此时 isBatchingUpdates 为false,
isRendering 为 false,直接执行 performSyncWork。
performSyncWork
Initial mount 和事件都是同步更新。在render中已接触过performSyncWork,但 render 和 更新略有不同。调用栈如下:
performWork
function performWork(minExpirationTime: ExpirationTime, isYieldy: boolean) {findHighestPriorityRoot();// 查找是否有更新;获得nextFlushedRoot等值if (isYieldy) {{//...有 查找到 nextFlushedRoot 、nextFlushedExpirationTimeperformWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false);findHighestPriorityRoot();}finishRendering();//没有更新,则结束渲染}
有点熟悉的味道,performWorkOnRoot 中执行的和之前的基本相同。
function performWorkOnRoot(root, expirationTime, isYieldy) {isRendering = true; // Check if this is async work or sync/expired work.if (!isYieldy) {var finishedWork = root.finishedWork;if (finishedWork !== null) {// This root is already complete. We can commit it.completeRoot(root, finishedWork, expirationTime);} else {root.finishedWork = null;var timeoutHandle = root.timeoutHandle;if (timeoutHandle !== noTimeout) {root.timeoutHandle = noTimeout;cancelTimeout(timeoutHandle);}renderRoot(root, isYieldy);//渲染rootfinishedWork = root.finishedWork;if (finishedWork !== null) {// We've completed the root. Commit it.completeRoot(root, finishedWork, expirationTime);}}} else {//...}isRendering = false;}
更新时会从ReactRoot开始,创建整棵React Tree树,在渲染的过程中复用fiber。
renderRoot
function renderRoot(root: FiberRoot, isYieldy: boolean): void {flushPassiveEffects();isWorking = true;if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) {// Reset the stack and start working from the root.resetStack();nextRoot = root;nextRenderExpirationTime = expirationTime;//更新,也是走此处,注意此时 nextUnitOfWork 被赋值nextUnitOfWork = createWorkInProgress(nextRoot.current,null,nextRenderExpirationTime);root.pendingCommitExpirationTime = NoWork;}var didFatal = false;startWorkLoopTimer(nextUnitOfWork); //开始 "(React Tree Reconciliation)"do {try { workLoop(isYieldy); } catch (thrownValue) {//异常处理,此处省略 }break;} while (true);// We're done performing work. Time to clean up.isWorking = false;ReactCurrentDispatcher.current = null;resetContextDependences();resetHooks();// We completed the whole tree.const didCompleteRoot = true;stopWorkLoopTimer(interruptedBy, didCompleteRoot);// 删除 "(React Tree Reconciliation)"//....// Ready to commit.onComplete(root, rootWorkInProgress, expirationTime);}
createWorkInProgress
在更新中,这个是我们接触较多的方法。第一次执行时 current.alternate 被赋值为 workInProgress。
function createWorkInProgress(current, pendingProps, expirationTime) {var workInProgress = current.alternate;if (workInProgress === null) {workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode);workInProgress.elementType = current.elementType;workInProgress.type = current.type;workInProgress.stateNode = current.stateNode;workInProgress.alternate = current;current.alternate = workInProgress;//一直保存 work.} else {workInProgress.pendingProps = pendingProps; // We already have an alternate.// Reset the effect tag.workInProgress.effectTag = NoEffect; // The effect list is no longer valid.workInProgress.nextEffect = null;workInProgress.firstEffect = null;workInProgress.lastEffect = null;if (enableProfilerTimer) {workInProgress.actualDuration = 0;workInProgress.actualStartTime = -1;}}workInProgress.childExpirationTime = current.childExpirationTime;workInProgress.expirationTime = current.expirationTime;//此时是0workInProgress.child = current.child;workInProgress.memoizedProps = current.memoizedProps;//当前的propsworkInProgress.memoizedState = current.memoizedState;//当前的stateworkInProgress.updateQueue = current.updateQueue;// 当前的更新队列。setState时改的就是fiber队列workInProgress.contextDependencies = current.contextDependencies;workInProgress.sibling = current.sibling;workInProgress.index = current.index;workInProgress.ref = current.ref;if (enableProfilerTimer) {workInProgress.selfBaseDuration = current.selfBaseDuration;workInProgress.treeBaseDuration = current.treeBaseDuration;}return workInProgress;}
createWorkInProgress 是在更新时被调用。在更新过程中createWorkInProgress 起什么作用呢?
第一次是创建fiber,也就是current。
第二次current.alternate为null,以pendingProps等属性创建fiber,并复制current的属性。返回的workInProgress fiber 中新旧属性、新队列等信息。
第三次 current1 为第二次的workInProgress,current1.alternate为第二次的 current,此时以current1为模板得到 workInProgress2(被修改属性后的current)。返回workInProgress2就包含新旧属性、更新队列等信息。
第四次 current2是第三次的 workInProgress2,current2.alternate为第三次current1,此时以current2为模板得到workInProgress3(修改属性后的current1),返回workInProgress3中包含新旧属性、更新队列等信息。
第一次 第二次 第三次 第4次
current current workInProgress current1 workInProgress2 current2 workInProgress3
——- ——- ——————- ———- ————————- ————— —————————
|| || | | || || |
|| || | | || || |
|| || | | || || |
|| || | | || || |
|| || | | || || |
|| || | | || || |
在setState形成的队列保留在current上,在修改某属性值后,workInProgress添加新属性,无修改则保留之前的属性值。 队列是复用 current 上的 update。createWorkInProgress复用之前的fiber,适当修改属性,形成新的fiber。
createWorkInProgress 总的值是复制的,若值是对象,则可实时看到最新值。
dom 对应的fiber
生成的dom对应有相关的fiber,而这个fiber指向上面的 || 表示的树。调用 setState 执行 enqueueSetState时,会发现fiber中 memoizedState 并不是最新值。
var classComponentUpdater = {isMounted: isMounted,enqueueSetState: function enqueueSetState(inst, payload, callback) {var fiber = get(inst);//此实例 inst 的fiber,指向上面的 || 标识的树。var currentTime = requestCurrentTime();var expirationTime = computeExpirationForFiber(currentTime, fiber);var update = createUpdate(expirationTime);update.payload = payload;if (callback !== undefined && callback !== null) {update.callback = callback;}flushPassiveEffects();enqueueUpdate(fiber, update);scheduleWork(fiber, expirationTime);}}
假如有以下示例:
class App extends Component {state={count: 0}onClickFn = ()=>{this.setState({ count: this.state.count + 1 })}render() {return (<div id="appId"><span onClick={ this.onClickFn }点击 { this.state.count }</span></div>)}}ReactDOM.render(<App/>, document.getElementById('root'));
此处只统计在 enqueueSetState 中的 var fiber = get(inst) 对象的值,来说明dom与fiber 及 workInProgress的关系。
| state | 操作 | current(||) memoizedState 值 | 结果 state的值 |
|---|---|---|---|
| { count: 0 } | { count: 0 } | ||
| { count: 0 } | 点击span | { count: 0 } | { count: 1 } |
| { count: 1 } | 点击span | { count: 0 } | { count: 2 } |
| { count: 2 } | 点击span | { count: 2 } | { count: 3 } |
| { count: 3 } | 点击span | { count: 2 } | { count: 4 } |
| { count: 4 } | 点击span | { count: 4 } | { count: 5 } |
此处的 fiber 是上一次计算的结果。由 createWorkInProgress 中的 || 与 | 交换可知,|| 在第三次 和 第五次 看到 最新值。
交换
renderRoot 完成整棵树后,root.current.alternate 是当前的rootWorkInProgress,然后在onComplete中记录值;
交换是在 commitRoot 中完成,代码是 root.current = rootWorkInProgress。由于值是对象类型,且是相互复用,所以一个上面改,两个都变。
function performWorkOnRoot(root, expirationTime, isYieldy) {//...renderRoot(root, isYieldy);finishedWork = root.finishedWork;if (finishedWork !== null) {completeRoot(root, finishedWork, expirationTime);}//...}function renderRoot(){//...var rootWorkInProgress = root.current.alternate;//此处为交换点//...onComplete(root, rootWorkInProgress, expirationTime);}function onComplete(root, finishedWork, expirationTime) {root.pendingCommitExpirationTime = expirationTime;root.finishedWork = finishedWork;}function completeRoot(root, finishedWork, expirationTime) {//...root.finishedWork = null; //此处清空//...commitRoot(root, finishedWork);}function commitRoot(){//...省略代码root.current = finishedWork; //root为 FiberRoot//...}
beginWork
此时 renderExpirationTime是 1073741823,workInProgress.expirationTime 是0;current$$1是fiber;
function beginWork(current: Fiber | null, workInProgress: Fiber, renderExpirationTime: ExpirationTime): Fiber | null {const updateExpirationTime = workInProgress.expirationTime;if (current !== null) {const oldProps = current.memoizedProps;const newProps = workInProgress.pendingProps;if (oldProps !== newProps || hasLegacyContextChanged()) {didReceiveUpdate = true;} else if (updateExpirationTime < renderExpirationTime) {didReceiveUpdate = false;switch (workInProgress.tag) {case HostRoot:pushHostRootContext(workInProgress);resetHydrationState();break;case HostComponent:pushHostContext(workInProgress);break;case ClassComponent: {const Component = workInProgress.type;if (isLegacyContextProvider(Component)) {pushLegacyContextProvider(workInProgress);}break;}}// 更新执行此处return bailoutOnAlreadyFinishedWork(current,workInProgress,renderExpirationTime);}}}
在beginWork中会复用之前已完成的work,而不是重新创建fiber树。
function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) {cancelWorkTimer(workInProgress);if (current$$1 !== null) {workInProgress.contextDependencies = current$$1.contextDependencies;}if (enableProfilerTimer) {stopProfilerTimerIfRunning(workInProgress);}var childExpirationTime = workInProgress.childExpirationTime;if (childExpirationTime < renderExpirationTime) {return null;} else {cloneChildFibers(current$$1, workInProgress);//clone子项return workInProgress.child;//返回第一项}}//clone子fiberfunction cloneChildFibers(current$$1, workInProgress) {if (workInProgress.child === null) { return; }var currentChild = workInProgress.child;//拿到子fiber//重点,复用的是currentChild.pendingProps,这就导致下次循环中oldProps === newProps 的出现var newChild = createWorkInProgress(currentChild, currentChild.pendingProps,currentChild.expirationTime);workInProgress.child = newChild;newChild.return = workInProgress;while (currentChild.sibling !== null) {// 修改兄弟节点currentChild = currentChild.sibling;//复制兄弟节点,也是 pendingPropsnewChild = newChild.sibling = createWorkInProgress(currentChild,currentChild.pendingProps,currentChild.expirationTime);newChild.return = workInProgress;}newChild.sibling = null;//经过上面的循环,newChild已执行最后的兄弟节点}
updateClassComponent
function updateClassComponent(current$$1, workInProgress,Component, nextProps, renderExpirationTime) {//...省略var instance = workInProgress.stateNode;var shouldUpdate = void 0;if (instance === null) {//...省略} else if (current$$1 === null) {//...省略}else{shouldUpdate = updateClassInstance(current$$1, workInProgress,Component, nextProps, renderExpirationTime);}var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component,shouldUpdate, hasContext, renderExpirationTime);//...省略return nextUnitOfWork;}
在updateClassInstance 中计算 state,执行componentWillUpdate、getDerivedStateFromProps或componentWillReceiveProps。标记componentDidUpdate、getSnapshotBeforeUpdate。
function updateClassInstance(current, workInProgress, ctor, newProps, renderExpirationTime) {var instance = workInProgress.stateNode;var oldProps = workInProgress.memoizedProps;instance.props = workInProgress.type === workInProgress.elementType ? oldProps :resolveDefaultProps(workInProgress.type, oldProps);var oldContext = instance.context;var contextType = ctor.contextType;var nextContext = void 0;if (typeof contextType === 'object' && contextType !== null) {nextContext = _readContext(contextType);} else {var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);}var getDerivedStateFromProps = ctor.getDerivedStateFromProps;var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' ||typeof instance.getSnapshotBeforeUpdate === 'function';// 新api getDerivedStateFromProps 和 componentWillReceiveProps 冲突if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' ||typeof instance.componentWillReceiveProps === 'function')) {if (oldProps !== newProps || oldContext !== nextContext) {callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext);}}resetHasForceUpdateBeforeProcessing();var oldState = workInProgress.memoizedState;var newState = instance.state = oldState;var updateQueue = workInProgress.updateQueue;//当前对象上的更新队列if (updateQueue !== null) {processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime);newState = workInProgress.memoizedState;//newState 诞生}if (oldProps === newProps && oldState === newState && !hasContextChanged()&& !checkHasForceUpdateAfterProcessing()) {//通常更新不符合此条件if (typeof instance.componentDidUpdate === 'function') {if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {workInProgress.effectTag |= Update;}}if (typeof instance.getSnapshotBeforeUpdate === 'function') {if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {workInProgress.effectTag |= Snapshot;}}return false;}if (typeof getDerivedStateFromProps === 'function') {//执行 getDerivedStateFromPropsapplyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);newState = workInProgress.memoizedState;}var shouldUpdate = checkHasForceUpdateAfterProcessing() ||checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps,oldState, newState, nextContext);if (shouldUpdate) {// 返回true和 false,有助于更新if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function'|| typeof instance.componentWillUpdate === 'function')) {startPhaseTimer(workInProgress, 'componentWillUpdate');if (typeof instance.componentWillUpdate === 'function') {instance.componentWillUpdate(newProps, newState, nextContext);}if (typeof instance.UNSAFE_componentWillUpdate === 'function') {instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext);}stopPhaseTimer();}if (typeof instance.componentDidUpdate === 'function') {//标记 UpdateworkInProgress.effectTag |= Update;}if (typeof instance.getSnapshotBeforeUpdate === 'function') {//标记 SnapshotworkInProgress.effectTag |= Snapshot;}} else {// 如果 shouldComponentUpdate 返回false。// 我们还应该更新memoized的props/state,以表明该工作可以重用if (typeof instance.componentDidUpdate === 'function') {if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {//条件workInProgress.effectTag |= Update;}}if (typeof instance.getSnapshotBeforeUpdate === 'function') {if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {//条件workInProgress.effectTag |= Snapshot;}}workInProgress.memoizedProps = newProps;workInProgress.memoizedState = newState;}instance.props = newProps;// 更新实例的propsinstance.state = newState;// 更新实例的stateinstance.context = nextContext;// 更新contextreturn shouldUpdate;}
在processUpdateQueue计算newState。 newProps是在执行组件render方法时得到。执行完此方法就更新了state、porps、context。
接着执行updateClassComponent 中 finishClassComponent。在finishClassComponent 中调用 instance.render()生成 nextChildren。之后与render时一样,调用reconcileChildren,调用栈如下:
调用与render 无异,只是在 reconcileChildren 中 current$$1.child有值,可以使用之前的fiber,最后也是使用createWorkInProgress 克隆fiber。
在 createWorkInProgress 中 current.alternate 为 nulll 会创建 fiber。第一次更新会为当前 fiber 的 alternate 赋值。
updateHostComponent
和render的updateHostComponent基本一致。beginWork的updateHostComponent 主要用于生成子 fiber。
function updateHostComponent(current$$1, workInProgress, renderExpirationTime) {pushHostContext(workInProgress);if (current$$1 === null) {tryToClaimNextHydratableInstance(workInProgress);}var type = workInProgress.type;var nextProps = workInProgress.pendingProps;var prevProps = current$$1 !== null ? current$$1.memoizedProps : null;var nextChildren = nextProps.children;var isDirectTextChild = shouldSetTextContent(type, nextProps);if (isDirectTextChild) {nextChildren = null;} else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {workInProgress.effectTag |= ContentReset;}markRef(current$$1, workInProgress);if (renderExpirationTime !== Never && workInProgress.mode & ConcurrentMode&& shouldDeprioritizeSubtree(type, nextProps)) {workInProgress.expirationTime = workInProgress.childExpirationTime = Never;return null;}reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);return workInProgress.child;}
updateHostText
function updateHostText(current, workInProgress) {if (current === null) {tryToClaimNextHydratableInstance(workInProgress);}return null;}
completeUnitOfWork
beginWork中 执行组件中的生命周期,并为组件标记effectTag。completeUnitOfWork 中则为HostText、HostComponent 标记effectTag。
function completeUnitOfWork(workInProgress) {while (true) {var current$$1 = workInProgress.alternate;var returnFiber = workInProgress.return;var siblingFiber = workInProgress.sibling;//...nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime);//...//... effect 链表//...省略}return null;}function completeWork(current, workInProgress, renderExpirationTime) {var newProps = workInProgress.pendingProps;switch (workInProgress.tag) {//...case HostText:{var newText = newProps;if (current && workInProgress.stateNode != null) {var oldText = current.memoizedProps;updateHostText$1(current, workInProgress, oldText, newText);} else {//创建text}break;}case HostComponent:{popHostContext(workInProgress);var rootContainerInstance = getRootHostContainer();var type = workInProgress.type;if (current !== null && workInProgress.stateNode != null) {updateHostComponent$1(current, workInProgress, type, newProps,rootContainerInstance);if (current.ref !== workInProgress.ref) {markRef$1(workInProgress);}} else { //省略 创建 host Componennt }break;}}//....}
completeWork 解析的就是 HostComponent、HostText。
updateHostComponent$1
updateHostComponent主要用于标记 dom 属性的变化,返回更新队列。
updateHostComponent$1 = function updateHostComponent$1(current, workInProgress, type,newProps, rootContainerInstance) {var oldProps = current.memoizedProps;if (oldProps === newProps) { return; }var instance = workInProgress.stateNode;var currentHostContext = getHostContext();var updatePayload = prepareUpdate(instance, type, oldProps, newProps,rootContainerInstance, currentHostContext);workInProgress.updateQueue = updatePayload;if (updatePayload) {markUpdate(workInProgress);}};function prepareUpdate(domElement, type, oldProps,newProps, rootContainerInstance, hostContext) {return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance);}//计算属性 packages\react-dom\src\client\ReactDOMComponent.jsfunction diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) {// 对比STYLE$1// 对比更新的属性return updatePayload}
updateHostText$1
updateHostText 用于标记文本的更新。
//文本更新updateHostText$1 = function updateHostText$1(current, workInProgress, oldText, newText) {if (oldText !== newText) { markUpdate(workInProgress);//标记有更新 }}function markUpdate(workInProgress) {workInProgress.effectTag |= Update;}
diff
diff基本是在React Tree Reconciliation中。
- beginWork 中更多偏向创建fiber。对组件classComponent:调用组件的生命周期、标记组件的生命周期,生成子项fiber等;对元素HostComponent:主要生成子项fiber;对于HostText,基本属于忽略状态。
- 在 reconcileChildren 生成子fiber时,会增删并标记fiber,删除的 fiber 只添加在 effect 链上,未在fibers中;
- 在 completeWork 中主要对比 HostComponent 的属性 、HostText的值。对于 HostComponent来说,调用 diffProperties 逐项对比属性的值,若属性有更新则标记,并更新属性保存在workInProgress.updateQueue中;对于HostText来说,对比oldText和newText的值,若不相等则标记更新;对于classComponent,基本是忽略。
