React re-renders components. Solid updates the exact DOM nodes that changed. No virtual DOM, no reconciliation — just surgical updates.
Why SolidJS Signals?
Solid's reactivity system inspired Angular Signals, Svelte 5 Runes, and Vue's Composition API. It is the original fine-grained reactivity for JavaScript.
Core Primitives
createSignal
import { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
Notice: count() — signals are functions. The component function runs ONCE. Only the {count()} expression re-evaluates.
createEffect
import { createSignal, createEffect } from 'solid-js';
function App() {
const [name, setName] = createSignal('Alice');
createEffect(() => {
console.log('Name changed:', name());
document.title = `Hello, ${name()}`;
});
return <input value={name()} onInput={e => setName(e.target.value)} />;
}
createMemo (Computed)
import { createSignal, createMemo } from 'solid-js';
function App() {
const [items, setItems] = createSignal([1, 2, 3, 4, 5]);
const [filter, setFilter] = createSignal(0);
const filtered = createMemo(() => items().filter(i => i > filter()));
const total = createMemo(() => filtered().reduce((a, b) => a + b, 0));
return (
<div>
<p>Filtered: {filtered().join(', ')}</p>
<p>Total: {total()}</p>
<input type="number" value={filter()} onInput={e => setFilter(+e.target.value)} />
</div>
);
}
Stores (Deep Reactivity)
import { createStore, produce } from 'solid-js/store';
function TodoApp() {
const [state, setState] = createStore({
todos: [
{ id: 1, text: 'Learn Solid', done: false },
{ id: 2, text: 'Build app', done: false },
],
filter: 'all',
});
const toggle = (id: number) => {
setState(produce(s => {
const todo = s.todos.find(t => t.id === id);
if (todo) todo.done = !todo.done;
}));
};
const addTodo = (text: string) => {
setState('todos', todos => [...todos, { id: Date.now(), text, done: false }]);
};
return (
<ul>
<For each={state.todos}>
{(todo) => (
<li onClick={() => toggle(todo.id)}>
{todo.done ? '(done) ' : ''}{todo.text}
</li>
)}
</For>
</ul>
);
}
Control Flow Components
import { Show, For, Switch, Match } from 'solid-js';
function App() {
const [user, setUser] = createSignal(null);
const [items] = createSignal(['a', 'b', 'c']);
const [status] = createSignal('loading');
return (
<div>
<Show when={user()} fallback={<p>Not logged in</p>}>
{(u) => <p>Hello, {u().name}</p>}
</Show>
<For each={items()}>
{(item, index) => <p>{index()}: {item}</p>}
</For>
<Switch>
<Match when={status() === 'loading'}>Loading...</Match>
<Match when={status() === 'error'}>Error!</Match>
<Match when={status() === 'success'}>Done!</Match>
</Switch>
</div>
);
}
Resources (Async Data)
import { createResource, Suspense } from 'solid-js';
const fetchUser = async (id: string) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
};
function UserProfile(props: { id: string }) {
const [user] = createResource(() => props.id, fetchUser);
return (
<Suspense fallback={<p>Loading...</p>}>
<Show when={user()}>
{(u) => <h2>{u().name}</h2>}
</Show>
</Suspense>
);
}
SolidJS vs React
| Feature | SolidJS | React |
|---|---|---|
| Reactivity | Fine-grained signals | Re-render entire component |
| Virtual DOM | No | Yes |
| Component runs | Once | Every update |
| Bundle Size | 7KB | 40KB+ |
| Speed | Fastest | Good |
| Hooks Rules | None | Many rules |
Need reactive data feeds? Check out my Apify actors — real-time data extraction for reactive UIs. For custom solutions, email spinov001@gmail.com.
Top comments (0)