Reactivity

How each frontend framework tracks state changes and propagates them to the UI, from hook-based re-renders to fine-grained signals.

React

React reactivity is coarse-grained: calling a state setter (useState/useReducer) schedules a re-render of the whole component function, and the resulting virtual DOM is diffed to find what actually changed. There is no automatic dependency tracking, so avoiding unnecessary re-renders relies on manual memoization (useMemo, useCallback, React.memo).

Vue

Vue wraps data in Proxies (Vue 3) whose getters and setters automatically track which parts of the UI depend on which properties. This gives fine-grained reactivity without needing a virtual-DOM-wide re-render or manual dependency arrays.

Svelte

Svelte’s reactivity is handled by its compiler: assignments to reactive variables trigger only the compiled update code that depends on them. Svelte 5 formalizes this further with signal-like runes such as $state and $derived.

Angular

Angular has historically relied on zone.js to detect when async operations complete and re-check the component tree for changes (“dirty checking”). It is moving toward an explicit Signals API for opt-in, fine-grained reactivity that doesn’t require zone.js at all.

SolidJS

SolidJS is built around signals — primitive reactive values that track their subscribers directly at the point of use. Component functions run once to set up these bindings, so there is no re-execution of component logic on updates, only the exact DOM binding refreshes.

Qwik

Qwik uses a signals-based model similar to Solid’s, but designed to be serializable: reactive subscriptions can be paused on the server and resumed on the client without re-running any component setup code.

Preact

Preact shares React’s hook-based reactivity (useState/useReducer causing function re-execution), while also offering Preact Signals as an opt-in, fine-grained alternative that updates DOM directly without re-rendering components.

Lit

Lit elements declare reactive properties that automatically trigger a re-render of the element’s template when their values change, using simple property/attribute change observation rather than a dependency-tracking system.

Alpine.js

Alpine wraps the object passed to x-data in a reactive Proxy, similar in spirit to Vue’s approach, so any bound DOM automatically updates when a tracked property is mutated.

Ember

Ember uses explicit tracked properties (the @tracked decorator); Glimmer components autotrack which tracked properties are read during rendering and re-render only when those specific properties change.