The Virtual DOM
Phases 1-2 built the when - knowing the moment data changes. Now the what: what should the screen look like? React's founding idea (which our React guide's phase 1 described from the outside) is that UI should be a description - a cheap, throwaway JavaScript object - produced fresh from your data every time. Today you build the describer; phase 4 compares descriptions; phase 5 connects them to your reactivity engine.
h(): the element factory
A UI description needs three facts per element: what tag, what attributes, what's inside. So:
// Describe a product card - no DOM involved, this is just data:
const card = ;
console.log;
What just happened: h (the traditional name - "hyperscript") builds a plain object: a
virtual node, or vnode. Children can be more vnodes or bare strings (text). ...children
gathers everything after props; .flat() lets callers pass arrays (you'll see why in a moment).
The printout is the whole point: your UI is now data - inspectable, comparable, cheap to make
and throw away.
📝 Terminology: when our React guide said JSX compiles to createElement calls returning
"description objects" - this is that, minus the compiler. <h3>Kettle</h3> and
h('h3', null, 'Kettle') are the same sentence in two spellings.
Describing dynamically: it's just JavaScript
Because descriptions are built by function calls, all of JavaScript is your template language:
const vtree = ;
console.log;
What just happened: TodoList is a component - a plain function from data to description,
which is all a component fundamentally is. Conditionals are ternaries, lists are map - the
exact idioms our React guide teaches, revealed as ordinary code because that's all they ever
were. The map returns an array of vnodes inside the children list - which is why h flattens.
render(): description to HTML
A description is only useful if something realizes it. Browsers realize DOM nodes; for a runnable
console project, we'll realize HTML text - the logic is identical, minus document.createElement:
const page = ;
console.log;
What just happened: a recursive walk - strings render as themselves, vnodes render as a tag,
its attributes, and its recursively-rendered children. Notice two framework behaviors emerging
naturally: false/null children render as nothing (that's why {cond && <X/>} works in JSX),
and boolean props render as bare attributes (disabled) or vanish (disabled: false) - the
attribute-vs-property care our Angular guide's phase 2 made a fuss about, now visible from the
implementing side.
Your turn
Real renderers must escape text - otherwise user data containing < breaks the page (or worse:
injected scripts - this is XSS, the reason React strings are safe by default). Add escaping:
// A user "typed" this into a comment box:
const evil = ;
console.log;
// Goal: <p><script>steal(cookies)</script> & fun</p>
Recap
h(type, props, ...children)builds vnodes - plain objects describing UI. JSX is this with nicer clothes.- Components are functions from data to vnode trees; conditionals and lists are just JavaScript.
- A renderer is a recursive walk realizing descriptions - as HTML here, as DOM nodes in the real
thing; skipping
false/nullis why&&-rendering works. - Escaping text at render time is why frameworks are XSS-safe by default.
- Descriptions are cheap and comparable - and comparing two of them is phase 4.
← Phase 2: Effects and Computed · Guide overview · Phase 4: The Diff →