DEV Community

Alex Spinov
Alex Spinov

Posted on

SolidJS Has a Free Reactive Framework That Is Faster Than React Will Ever Be

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>;
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Effects

import { createEffect, onCleanup } from "solid-js";

createEffect(() => {
  // Auto-tracks dependencies
  console.log(`Count is now ${count()}`);

  const timer = setInterval(() => {}, 1000);
  onCleanup(() => clearInterval(timer));
});
Enter fullscreen mode Exit fullscreen mode

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;
}));
Enter fullscreen mode Exit fullscreen mode

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

<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>
  );
}
Enter fullscreen mode Exit fullscreen mode

SolidStart (Full-Stack Framework)

npm init solid@latest my-app
Enter fullscreen mode Exit fullscreen mode

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)