/**
* 此算法不能通过双指针进行两端搜索优化,因为 current Fiber 是通过 sibling 指针形成的单链表,没有 back pointer
*/
function reconcileChildrenArray(
returnFiber: Fiber,
currentFirstChild: Fiber | null,
newChildren: Array<any>,
lanes: Lanes,
): Fiber | null {
// 保存最终的 newFiber
let resultingFirstChild: Fiber | null = null;
let previousNewFiber: Fiber | null = null;
let oldFiber = currentFirstChild;
// 上一个插入点(实际上保存的是 oldFiber.index)
let lastPlacedIndex = 0;
let newIdx = 0;
let nextOldFiber = null;
// 第一部分遍历
for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
// 说明位置已经改变过,将跳出本循环,直接走到第三部分遍历
if (oldFiber.index > newIdx) {
// ...
} else {
nextOldFiber = oldFiber.sibling;
}
// 如果 key 不相同,直接返回 null,跳出循环走到第二部分遍历
// 如果 key 相同,类型相同,则复用旧节点,否则创建新节点
const newFiber = updateSlot(
returnFiber,
oldFiber,
newChildren[newIdx],
lanes,
);
// 如果 key 不相同跳出循环
if (newFiber === null) {
// ...
break;
}
if (shouldTrackSideEffects) {
// newFiber.alternate === null 说明是新创建的节点,即此时 key 相同,类型不同,需将 oldFiber 标记为删除
if (oldFiber && newFiber.alternate === null) {
deleteChild(returnFiber, oldFiber);
}
}
// 更新 lastPlacedIndex
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = newFiber;
} else {
// 将 newFiber 串联成新的链表
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
// newChildren 遍历完成
if (newIdx === newChildren.length) {
// 如果有多余的节点,说明新节点变少了,需要将多余的节点标记为删除,再返回 newFiber
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
// newChildren 未遍历完成,oldFiber 遍历完成,说明新节点数量增多了,需要将多余的节点生成 workInProgress Fiber,并标记为插入,再返回新节点
if (oldFiber === null) {
// 第二部分遍历
for (; newIdx < newChildren.length; newIdx++) {
const newFiber = createChild(returnFiber, newChildren[newIdx], lanes);
if (newFiber === null) {
continue;
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
// ...
}
return resultingFirstChild;
}
// 如果 newChildren 和 oldFiber 都没有遍历完,需要将 oldFiber 节点及其兄弟节点
// 以 (oldFiber.key || oldFiber.index) 为 key, oldFiber 为 value,生成一个 Map 对象,方便快速查找
const existingChildren = mapRemainingChildren(returnFiber, oldFiber);
// 继续遍历 newChildren(第三部分遍历)
for (; newIdx < newChildren.length; newIdx++) {
const newFiber = updateFromMap(
existingChildren,
returnFiber,
newIdx,
newChildren[newIdx],
lanes,
);
if (newFiber !== null) {
if (shouldTrackSideEffects) {
// 说明存在复用 oldFiber,需要将其在 Map 中移除,保证后续不会把它标记为删除
if (newFiber.alternate !== null) {
existingChildren.delete(
newFiber.key === null ? newIdx : newFiber.key,
);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
// ...
}
}
//...
if (shouldTrackSideEffects) {
// 剩余的节点都需要标记为删除
existingChildren.forEach(child => deleteChild(returnFiber, child));
}
return resultingFirstChild;
}