SolidJS: Signals, Effects & Memos
SolidJS is a declarative JSX-based UI library built around fine-grained reactivity rather than a virtual DOM. Unlike React, a Solid component function runs only ONCE during setup -- reactivity happens through signal updates writing directly to specific DOM nodes, not by re-invoking the whole component.
createSignal: Reactive Primitives
import { createSignal } from 'solid-js'
function Counter() {
const [count, setCount] = createSignal(0)
return (
<button onClick={() => setCount(count() + 1)}>
Count: {count()}
</button>
)
}
// count() must be CALLED as a function to read its value -- this is
// what lets Solid track exactly where the signal is being read,
// enabling updates to only the specific DOM node that depends on itcreateEffect & createMemo
import { createSignal, createEffect, createMemo } from 'solid-js'
const [count, setCount] = createSignal(0)
// Automatically re-runs whenever count changes -- no manual
// dependency array needed, unlike React's useEffect(fn, [count])
createEffect(() => {
console.log('count is now', count())
})
// Derived, CACHED value -- only recomputes when count actually
// changes; multiple reads of doubled() share the same computation
const doubled = createMemo(() => count() * 2)Why Props Shouldn't Be Destructured
// WRONG -- destructuring captures a static snapshot at setup time,
// since the component function only runs once
function Greeting({ name }: { name: string }) {
return <p>Hello, {name}</p> // never updates if `name` prop changes
}
// CORRECT -- accessing props.name directly preserves reactivity,
// re-reading the live value each time
function Greeting(props: { name: string }) {
return <p>Hello, {props.name}</p>
}Control Flow: Show, For, Switch/Match
import { Show, For, Switch, Match } from 'solid-js'
// Conditional rendering -- a plain `if` at the component-body level
// only evaluates once at setup, so <Show> exists as a reactive
// primitive that correctly toggles as `when` changes over time
<Show when={loggedIn()} fallback={<Login />}>
<Dashboard user={user()} />
</Show>
// Optimized list rendering -- reuses DOM nodes by item identity,
// rather than a plain .map() which loses fine-grained per-item tracking
<For each={items()}>
{(item) => <li>{item.name}</li>}
</For>
// Multi-branch conditional
<Switch>
<Match when={status() === 'loading'}><Spinner /></Match>
<Match when={status() === 'error'}><ErrorMessage /></Match>
</Switch>Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free