DOM-Diff
单节点
function reconcileSingleElement(returnFiber, currentFirstChild, element) {
const key = element.key;
let child = currentFirstChild;
while (child !== null) {
if (child.key == key) {
if (child.type == element.type) {
deleteRemainingChildren(returnFiber, child.sibling);
const existing = useFiber(child, element.props);
existing.return = returnFiber;
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
...
key 不同,删除老的 fiber,根据新的虚拟 DOM 创建新的 fiber
function reconcileSingleElement(returnFiber, currentFirstChild, element) {
const key = element.key;
let child = currentFirstChild;
while (child !== null) {
if (child.key == key) {
if (child.type == element.type) {
...
} else {
deleteRemainingChildren(returnFiber, child);
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
const created = createFiberFromElement(element);
created.return = returnFiber;
return created;
}
多节点的 DOM-Diff
function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren) {
let resultingFirstChild = null;
let previousNewFiber = null;
let newIndex = 0;
let oldFiber = currentFirstChild;
let nextOldFiber = null;
let lastPlacedIndex = 0;
....
if (oldFiber == null) {
for (; newIndex < newChildren.length; newIndex++) {
const newFiber = createChild(returnFiber, newChildren[newIndex]);
if (newFiber == null) continue;
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIndex);
if (previousNewFiber == null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
}
}
....
return resultingFirstChild;
}
- key 和 type 既有相同的也有不同的,复用老的并且更新属性,
function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren) {
let resultingFirstChild = null;
let previousNewFiber = null;
let newIndex = 0;
let oldFiber = currentFirstChild;
let nextOldFiber = null;
let lastPlacedIndex = 0;
for (; oldFiber !== null && newIndex < newChildren.length; newIndex++) {
nextOldFiber = oldFiber.sibling;
const newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIndex]);
if (newFiber == null) break;
if (shouldTrackSideEffects) {
if (oldFiber && newFiber.alternate == null) {
deleteChild(returnFiber, oldFiber);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIndex);
if (previousNewFiber == null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
if (newIndex === newChildren.length) {
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
if (oldFiber == null) {
for (; newIndex < newChildren.length; newIndex++) {
const newFiber = createChild(returnFiber, newChildren[newIndex]);
if (newFiber == null) continue;
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIndex);
if (previousNewFiber == null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
}
}
const existingChildren = mapRemainingChildren(returnFiber, oldFiber);
for (; newIndex < newChildren.length; newIndex++) {
const newFiber = updateFromMap(
existingChildren,
returnFiber,
newIndex,
newChildren[newIndex]
);
if (newFiber !== null) {
if (shouldTrackSideEffects) {
if (newFiber.alternate !== null) {
existingChildren.delete(
newFiber.key == null ? newIndex : newFiber.key
);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIndex);
if (previousNewFiber == null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
}
}
if (shouldTrackSideEffects) {
existingChildren.forEach((child) => deleteChild(returnFiber, child));
}
return resultingFirstChild;
}