Solid.js vs React: Two Models of Reactivity Compared
Solid.js uses fine-grained signals and no virtual DOM; React re-renders components and diffs. How the two reactivity models differ in practice.
Solid.js and React both let you write UI as JSX components, but they update the DOM through fundamentally different mechanisms. React re-runs a component function and diffs the result against a virtual DOM to figure out what changed. Solid compiles JSX into direct DOM instructions up front and updates only the exact nodes tied to a piece of state that changed — no diffing, and in most cases, no re-running the component function at all.
How React updates the DOM
React’s model centers on re-rendering. When state changes, React calls the component function again, producing a new tree of React elements. It then diffs that tree against the previous one (reconciliation) and applies the minimal set of DOM mutations needed to catch up. Hooks like useState and useMemo exist largely to manage this re-render cycle — memoization is opt-in and manual, because without it, child components re-render whenever their parent does.
This model is conceptually simple: a component is a pure function of its props and state, and the framework figures out the DOM diff for you. The tradeoff is that “what changed” has to be recomputed on every update, even when only one small piece of the UI actually needs to change.
How Solid updates the DOM
Solid uses signals — reactive values that track their own subscribers. A component function in Solid runs exactly once, at creation. JSX expressions that reference a signal are compiled into small reactive computations wired directly to the DOM nodes they affect. When a signal updates, only those specific bindings re-run; the surrounding component function does not execute again.
This is “fine-grained” reactivity: instead of one function that produces a whole subtree and gets diffed, each piece of dynamic output is its own independent, tracked expression. There’s no virtual DOM to build or compare, because the framework already knows, at compile time, exactly which DOM node a given signal touches.
Comparing the two models
| React | Solid | |
|---|---|---|
| Update mechanism | Re-render + virtual DOM diff | Fine-grained signal updates, direct DOM writes |
| Component function re-runs | On every state change (unless memoized) | Once, at creation |
| Memoization | Manual (useMemo, useCallback, memo) | Automatic via signal tracking |
| Reactive primitive | State + re-render | Signals (see signals in frontend state) |
| JSX | Runtime, produces React elements | Compiled to direct DOM operations |
| Ecosystem size | Very large | Smaller, growing |
Why this distinction matters in practice
The practical consequence of fine-grained reactivity is that Solid apps typically don’t need the manual memoization that React apps rely on for performance. A useMemo or React.memo wrapper exists to stop unnecessary re-renders from propagating down the tree; in Solid, there’s no re-render to propagate in the first place, because updates only ever touch the specific DOM bindings tied to the signal that changed.
This doesn’t automatically make Solid “faster” for every workload — both frameworks are fast enough for the overwhelming majority of applications, and UI performance bottlenecks are more often about network requests, layout thrashing, or unnecessary work in event handlers than about the rendering model itself. See the Core Web Vitals guide for the metrics that actually govern perceived performance in production. The distinction matters more for how you reason about the code: in React you’re always asking “what re-renders when this changes,” while in Solid you’re asking “what’s subscribed to this signal.”
API surface and mental model
React’s hooks (useState, useEffect, useMemo) and Solid’s primitives (createSignal, createEffect, createMemo) look similar on the surface, which makes the frameworks easy to read side by side. The key difference is when things run. A React useEffect re-registers on every render where its dependencies changed; a Solid createEffect sets up a tracking scope once and re-runs only when a signal it reads changes — closer in spirit to how JavaScript closures capture the values they were created with, since Solid components don’t get a fresh closure per update the way React components do.
Solid also has no rules-of-hooks equivalent — no restriction against calling createSignal conditionally or in a loop — because signals aren’t tied to a per-render call order the way hooks are. That constraint in React exists specifically to let React match up hook calls between renders; since Solid components only run once, there’s no matching problem to solve.
Ecosystem and adoption
React’s ecosystem is far larger: more libraries, more hiring pools, more Stack Overflow answers, and broader framework support (Next.js, Remix, and others build directly on it). Solid’s ecosystem is smaller but has meta-frameworks of its own, and its API is close enough to React’s that migrating a team’s mental model is usually easier than migrating, say, to Svelte or Vue, each of which takes yet another approach to reactivity and compilation.
The takeaway
React re-renders components and diffs a virtual DOM to apply changes; Solid compiles JSX to direct DOM bindings driven by fine-grained signals, so only the exact values that changed touch the DOM. Neither model is strictly superior — React’s larger ecosystem and hiring pool are real advantages, while Solid’s approach removes an entire class of manual-memoization bugs by design. Choosing between them is less about raw performance and more about which mental model — “re-render and diff” or “track and update directly” — your team would rather reason about day to day.
Keep reading
Takina · · 4 min read Vue vs React: Which Framework Fits Your Project
Vue uses a template syntax with a reactive proxy system; React uses JSX with a virtual DOM. How the two frameworks differ and when to pick each.
Takina · · 5 min read Svelte vs React: Which Should You Choose?
Svelte compiles away at build time; React ships a runtime and virtual DOM. Bundle size, reactivity model, and ecosystem tradeoffs compared.
Takina · · 3 min read Getting Started with htmx: Interactive UIs Without a Framework
htmx lets you build dynamic, interactive pages with HTML attributes — no SPA, no build step. Learn the core ideas and ship a working live-search example in minutes.