Q23: Build a Basic Virtual DOM Tree Diffing Engine

Build a diffing engine that compares old and new Virtual DOM node trees recursively, generating patch descriptions for updates, replacements, and removals.

VNode Diffing Algorithm
function diff(oldVNode, newVNode) {
  if (newVNode === undefined) {
    return { type: 'REMOVE' };
  }
  if (typeof oldVNode === 'string' || typeof newVNode === 'string') {
    if (oldVNode !== newVNode) return { type: 'TEXT', text: newVNode };
    return null;
  }
  if (oldVNode.type !== newVNode.type) {
    return { type: 'REPLACE', newVNode };
  }
  
  const propsDiff = diffProps(oldVNode.props || {}, newVNode.props || {});
  const childrenDiff = diffChildren(oldVNode.children || [], newVNode.children || []);
  
  return {
    type: 'UPDATE',
    props: propsDiff,
    children: childrenDiff
  };
}

function diffProps(oldProps, newProps) {
  const patches = [];
  for (let key in newProps) {
    if (newProps[key] !== oldProps[key]) patches.push({ key, value: newProps[key] });
  }
  for (let key in oldProps) {
    if (!(key in newProps)) patches.push({ key, value: undefined });
  }
  return patches;
}

function diffChildren(oldChildren, newChildren) {
  const max = Math.max(oldChildren.length, newChildren.length);
  const childPatches = [];
  for (let i = 0; i < max; i++) {
    childPatches.push(diff(oldChildren[i], newChildren[i]));
  }
  return childPatches;
}
💡 Compares VNodes recursively, returning REPLACE patches when tag types change or UPDATE patches for modified props/children.
Key Takeaways
  • Compares VNodes recursively to calculate minimal structural edits.
  • Replaces entire subtrees when VNode type tags differ.
Knowledge Check

What patch action is returned when comparing two VNodes with different element type tags (e.g. div vs section)?