Skip to content
On this page

归阶段,主要执行 completeWork 逻辑

completeWork

js
function completeWork(current, wip, renderLanes) {
	//..
	switch (workInProgress.tag) {
		// 根据wip 的类型执行逻辑
		case HostComponent:
			if (current !== null && workInProgress.stateNode != null) {
				updateHostComponent(current, wip, type, newProps, rootContainerInstance)
			} else {
				// 首屏渲染逻辑
			}
	}
}


function updateHostComponent(current, wip, type, newProps, rootIns) {
	const instance = wip.stateNode
	const currentHostContext = getHostContext()
	const updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext)
	// 当前节点的更新队列任务
	workInProgress.updateQueue = updatePayload;
	if (updatePayload) {
      markUpdate(workInProgress);
    }
}

// 生成 updatePayload (也就是更新信息)
function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) {
	// ... 更新两个props
	return diffProperties(domElement, type, oldProps, newProps);
}

function diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) {
	// ... 根据 wip 的 type执行相应逻辑
	switch (tag) {
	// 主要针对三个表单组件
		case 'input':
		case 'select':
		case 'textarea':
			// ...
		default:
			lastProps = lastRawProps
			nextProps = nextRawProps
	}
	//...
	for (propKey in lastProps) {
		// 新旧都有的属性,或者新增的属性直接跳出循环
		if (nextProps.hasOwnProperty(propKey) 
			|| !lastProps.hasOwnProperty(propKey) 
			|| lastProps[propKey] == null) {
	      continue;
    }
    //...
	}
	for (propKey in nextProps) {
		var nextProp = nextProps[propKey]; // 新属性值
    var lastProp = lastProps != null ? lastProps[propKey] : undefined;
		if (!nextProps.hasOwnProperty(propKey) 
			|| nextProp === lastProp 
			|| nextProp == null && lastProp == null) {
			// 更新前后相等
      continue;
    }
    if (propKey === STYLE) {
	    // 传入的style 对象更新
    } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
	    // 传入的 dangerouslySetInnerHtml 更新
    } else if (propKey == CHILDREN) {
	    // 传入的children 更新
    } else {
	    (updatePayload = updatePayload || []).push(propKey, nextProp);
    }
	}
	//...
	return updatePayload
}

diffProperties 返回 updatePayload ,数据结构为数组 [propKey, propValue],返回赋值给 wip.updateQueue 同时,标记该 wip 有更新

js
function markUpdate(workInProgress) {
	workInProgress.flags |= Update;
}

最后,通过 commit 阶段进行渲染

completeUnitOfWork

更新过程中,不再参考首屏渲染的 DFS(深度优先)逐个节点进行渲染,而是在完成 completeWork 之后,将需要更新的 FiberNode 组装成链表 effectListcommit 阶段只需要更新这条链表

以上操作发生在 completeUnitOfWork

js
function completeUnitOfWork(unitOfWork) {
	let completedWork = unitOfWork
	do {
	
	// ...
		if ((completedWork.flags & Incomplete) === NoFlags) {
			let next;
      // 处理Fiber节点, 会调用渲染器
      // (调用react-dom包, 关联Fiber节点和dom对象, 绑定事件等)
      next = completeWork(current, completedWork, subtreeRenderLanes); 
      // 处理单个节点
      if (next !== null) {
        // 如果派生出其他的子节点, 则回到`beginWork`阶段进行处理
        workInProgress = next;
        return;
      }
      // 重置子节点的优先级
      resetChildLanes(completedWork);			
      if (returnFiber !== null 
				&& (returnFiber.flags & InComplete) === NoFlags) {
				// 当前 unitOfWork 没有未完成递归操作的父节点
				if (returnFiber.firstEffect === null) {
					returnFiber.firstEffect = completedWork.firstEffect
				}
				if (completedWork.lastEffect !== null) {
					if (returnFiber.lastEffect !== null) {
						returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
					}
					returnFiber.lastEffect = completedWork.lastEffect;
				}
			}
			const flags = completedWork.flags;
			if (flags > PerformedWork) {
				//PerformedWork是提供给 React DevTools读取的, 所以略过PerformedWork
				if (returnFiber.lastEffect !== null) {
					returnFiber.lastEffect.nextEffect = completedWork;
				} else {
					returnFiber.firstEffect = completedWork;
				}
				returnFiber.lastEffect = completedWork;
			}
		}
		const siblingFiber = completedWork.sibling;
    if (siblingFiber !== null) {
      // 如果有兄弟节点, 返回之后再次进入`beginWork`阶段
      workInProgress = siblingFiber;
      return;
    }
    // 移动指针, 指向下一个节点
    completedWork = returnFiber;
    workInProgress = completedWork;
	} while (completedWork !== null);
}

effectList中第一个Fiber节点保存在其 父节点 returnFiber.firstEffect,最后一个元素保存在returnFiber.lastEffect

  • 最后,所有包含 flagsFiberNode 都会被追加在 effectList 中,最终形成一条以rootFiber.firstEffect为起点的链表(指向第一个具有 flag 的叶节点)
  • 然后通过 nextEffect 指向下一个 带有 flags 的节点