Tags: web-dev concept

Reactivity

Date: 2026-08-19


The one question every framework has to answer: when a value changes, how do we know what to update? There are three families of answer, they differ mainly in when the dependency is worked out, and that timing decides almost everything else about how the framework feels.


Reactivity is the mechanism connecting a change in state to the specific DOM updates it requires.

Three families. The difference is when the framework learns what depends on what:

                 WHEN IS THE DEPENDENCY KNOWN?

RE-RUN + DIFF    never — recompute everything, compare, patch the difference
                 React
                 unit of work: the component

RUNTIME TRACKING at read time — a getter records who was reading it
                 Vue, Solid, Angular signals
                 unit of work: the expression

COMPILE-TIME     at build time — the compiler reads the source and emits
                 the update statements directly
                 Svelte
                 unit of work: the statement

Re-run and diff

State changes, the component function runs again from the top, produces a new description, and the framework compares it with the previous one to find the real DOM changes. See Virtual DOM.

The trade is honesty for work. Nothing has to be declared: any value read during render is a dependency by construction, so it can’t go stale. The cost is that the framework re-runs code that couldn’t possibly have changed, and the developer takes on a second job — telling it what to skip, through memoisation and stable references.

Characteristic failure: the stale closure. A function created in one render captures that render’s values; called later, it reports the past. Every “why is my count one behind” question is this.

Runtime dependency tracking

Reading a reactive value goes through a getter. If something is currently being computed, the getter records the pair. Writing notifies exactly those subscribers. See Signals.

The trade is bookkeeping for precision. Updates reach the single text node that changed without re-running the component, so cost scales with what changed rather than with tree size. The cost is that the tracking only works inside a reactive context — read a value outside one and you get a plain snapshot with no subscription, silently.

Characteristic failure: losing reactivity by destructuring. Pulling .value out into a local variable copies the number and drops the getter, so nothing ever updates again — and nothing errors.

Compile-time reactivity

The compiler analyses the source, builds the dependency graph statically, and emits imperative update code. No diffing algorithm ships to the browser and no dependency-tracking runtime does either.

The trade is flexibility for size. It’s the smallest and fastest of the three at runtime, and it needs the compiler to be able to see the assignment. Dynamism the compiler can’t follow has to be routed through explicit reactive primitives.

What this decides for you

Re-run + diffRuntime trackingCompiled
Update granularityComponent subtreeExpressionStatement
Cost scales withTree sizeNumber of subscribersNothing at runtime
Manual optimisationMemoisation, stable refsRareRare
Runtime shippedFramework + diffFramework + trackingAlmost none
Fails byRe-rendering too muchLosing the subscriptionCompiler can’t see it

Convergence is real, in one direction. React shipped a compiler that inserts memoisation for you; Angular made signals its reactivity model; Vue — signal-shaped from the start — added a compiled mode that skips diffing entirely; Svelte rebuilt its compiled reactivity on signals underneath. The industry decided fine-grained tracking was right — the surviving disagreement is whether you write it or a compiler infers it.

The thing worth carrying

Granularity is the whole story. Ask of any framework: when this one number changes, what is the smallest thing that runs again? A component, an expression, or an assignment. That single answer predicts its performance profile, its debugging experience, and which optimisations you’ll be asked to do by hand.