React re-renders entire component trees. SolidJS updates only the exact DOM nodes that changed — no virtual DOM, no diffing, no wasted work.
The Speed Difference
React: Component changes → re-run entire function → diff virtual DOM → patch real DOM
Solid: Signal changes → update exact DOM node → done
// React: this ENTIRE function re-runs on every count change
function Counter() {
const [count, setCount] = useState(0);
console.log("React: I run on EVERY update");
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
// Solid: this function runs ONCE, ever
function Counter() {
const [count, setCount] = createSignal(0);
console.log("Solid: I run ONCE, at creation");
return <button onClick={() => setCount(c => c + 1)}>{count()}</button>;
}
In Solid, the component function is a setup function, not a render function.
Core Primitives
Signals (State)
import { createSignal } from "solid-js";
const [name, setName] = createSignal("World");
const [count, setCount] = createSignal(0);
// Read: call the getter
console.log(name()); // "World"
console.log(count()); // 0
// Write: call the setter
setName("Solid");
setCount(prev => prev + 1);
Memos (Derived/Computed)
import { createMemo } from "solid-js";
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
const isEven = createMemo(() => count() % 2 === 0);
// Only recomputes when count changes
console.log(doubled()); // 0
Effects
import { createEffect, onCleanup } from "solid-js";
createEffect(() => {
// Auto-tracks dependencies
console.log(`Count is now ${count()}`);
const timer = setInterval(() => {}, 1000);
onCleanup(() => clearInterval(timer));
});
Stores (Nested Reactivity)
import { createStore, produce } from "solid-js/store";
const [state, setState] = createStore({
users: [
{ id: 1, name: "Alice", todos: [{ text: "Learn Solid", done: false }] },
{ id: 2, name: "Bob", todos: [] },
],
});
// Fine-grained updates — only affected DOM nodes update
setState("users", 0, "todos", 0, "done", true);
// Or use produce (Immer-like)
setState(produce((s) => {
s.users[0].todos[0].done = true;
}));
Control Flow (Compiled)
import { Show, For, Switch, Match } from "solid-js";
function App() {
return (
<>
<Show when={user()} fallback={<Login />}>
{(user) => <Profile user={user()} />}
</Show>
<For each={items()}>
{(item, index) => <div>{index()}: {item.name}</div>}
</For>
<Switch>
<Match when={status() === "loading"}>Loading...</Match>
<Match when={status() === "error"}>Error!</Match>
<Match when={status() === "success"}>Done!</Match>
</Switch>
</>
);
}
<For> is keyed by reference — no key prop needed. Items are never recreated on reorder.
Resources (Data Fetching)
import { createResource, Suspense } from "solid-js";
const [userId, setUserId] = createSignal(1);
const [user] = createResource(userId, async (id) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
});
function UserProfile() {
return (
<Suspense fallback={<p>Loading...</p>}>
<h1>{user()?.name}</h1>
</Suspense>
);
}
SolidStart (Full-Stack Framework)
npm init solid@latest my-app
File-based routing, server functions, SSR, streaming — all built-in.
Bundle Size
| Framework | TodoMVC Bundle |
|---|---|
| React 19 | 42KB |
| Vue 3 | 33KB |
| Svelte 5 | 6.5KB |
| SolidJS | 7KB |
Building performance-critical web apps? I create developer tools and data solutions. Email spinov001@gmail.com or check my Apify tools.
Top comments (0)