Rendering a vnode tree from scratch on every change would throw away the whole DOM each time — slow, and it loses focus, scroll, and selection. The virtual-DOM payoff comes from diffing: compare the new vnode tree against the old one and apply the minimum set of real-DOM changes. Same tag? Patch its props in place and recurse into children. Different tag or text? Replace just that node. This is React's reconciliation, in miniature.
Implement patch(parent, oldVNode, newVNode, index = 0) (with the given createElement/render). Mutate the DOM under parent so the child at index matches newVNode — updating props in place when the type is unchanged, replacing only when it truly changed, and recursing into children.
function patch(parent, oldVNode, newVNode, index = 0) {
// mutates parent.childNodes[index] to match newVNode
}
const oldV = h('div', { id: 'a' }, 'hi');
container.appendChild(render(oldV));
const node = container.firstChild;
patch(container, oldV, h('div', { id: 'b' }, 'hi'));
container.firstChild === node; // true — SAME node, only id changed to 'b'
changed(a, b) — true if the types differ, two primitives differ (text change), or two elements have different type (tag).Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.