How it works
The explanation, with examples you can run.
JSX builds plain objects
function Greeting({ name }: { name: string }) { return <p className="greet">Hello, {name}</p>} const element = <Greeting name="Ada" />A JSX tag compiles to a function call (jsx(Greeting, { name: "Ada" }) with the modern transform) that returns an element: a small object with a type, props and an optional key. Creating it does not call Greeting and does not touch the DOM. Here is the idea with a stand-in for jsx (a toy, not React's real function):
Press Run to see what your code prints, in order.
Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.
The element for <Greeting /> just records the function and its props. Only when React renders it does it call Greeting, getting back another description, this time of a p. React keeps going until it reaches host elements like p and div, which it knows how to create in the DOM.
State in, UI out
Because the output depends only on the inputs, the same component handles every state:
type Props = { items: string[]; loading: boolean } function List({ items, loading }: Props) { if (loading) return <p>Loading...</p> if (items.length === 0) return <p>Nothing yet</p> return ( <ul> {items.map((item) => ( <li key={item}>{item}</li> ))} </ul> )}There is no code for moving from "loading" to "three items". Each render describes the target, and React works out the DOM changes. That removes a whole class of bugs where the page ends up in a state no code path intended, because the steps were applied in an unexpected order.
Purity is the contract
React can only treat a component as a description if calling it has no side effects and gives the same result for the same inputs. So during render:
- Don't change variables or objects that existed before the call (props, state, module-level data).
- Don't touch the DOM, start timers, send requests or log analytics.
- Do create new local variables and objects freely; that's not a side effect.
React relies on this. It may render a component and throw the result away, render parts of the tree in a different order, or pause and resume (see transitions). In development, <StrictMode> calls every component twice to make impure ones misbehave visibly. Side effects belong in event handlers, which run because the user did something, or in effects, which run after React has updated the page.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.