| name | solid-syntax-signals |
| description | Use when creating signals, effects, memos, resources, or managing component lifecycle in SolidJS. Prevents React useState/useEffect anti-patterns that break fine-grained reactivity tracking. Covers createSignal, createEffect, createMemo, createResource, createRenderEffect, createComputed, batch, untrack, on, onMount, onCleanup, observable, and from. Keywords: createSignal, createEffect, createMemo, createResource, batch, untrack, onMount, onCleanup, SolidJS reactivity, signals.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires SolidJS 1.x/2.x with TypeScript. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
solid-syntax-signals
Quick Reference
All Reactive Primitives
| Primitive | Import | Purpose | Returns |
|---|
createSignal<T> | solid-js | Reactive state atom | [Accessor<T>, Setter<T>] |
createEffect | solid-js | Side effect on dependency change | void |
createMemo<T> | solid-js | Cached derived value (IS a reactive source) | Accessor<T> |
createResource<T> | solid-js | Async data with loading/error states | [Resource<T>, { mutate, refetch }] |
createRenderEffect | solid-js | Synchronous effect during render phase | void |
createComputed | solid-js | Before-render state synchronization | void |
batch | solid-js | Defer propagation until callback completes | T (return value) |
untrack | solid-js | Prevent dependency tracking | T (return value) |
on | solid-js | Explicit dependency specification for effects | EffectFunction |
onMount | solid-js | Run once after DOM mount (non-tracking) | void |
onCleanup | solid-js | Dispose resources on scope cleanup (LIFO) | void |
observable | solid-js | Convert signal to RxJS Observable | Observable<T> |
from | solid-js | Bridge external reactive source to signal | Accessor<T> |
Critical Warnings
ALWAYS call signal getters as functions: count(), NEVER count. Forgetting the parentheses reads the getter function itself, not the value, and breaks reactivity tracking.
NEVER use dependency arrays. SolidJS tracks dependencies automatically. Writing createEffect(() => { ... }, [dep]) does NOT work like React's useEffect.
NEVER destructure props or store objects. Destructuring reads values once and kills reactive tracking. ALWAYS access properties on the original object.
ALWAYS remember: the component function runs ONCE. Only reactive expressions (effects, memos, JSX bindings) re-execute. Top-level code is setup code, not render code.
NEVER return cleanup functions from effects. SolidJS uses onCleanup() as a separate call, not a return value like React's useEffect.
NEVER use createEffect for derived values. ALWAYS use createMemo instead. Effects are for side effects only.
Decision Tree: Which Primitive to Use
Need reactive state?
YES --> Simple value? --> createSignal
Complex/nested object? --> createStore (see solid-syntax-stores)
Need derived value?
YES --> Synchronous? --> createMemo
Asynchronous? --> createResource
Need side effect?
YES --> After render, DOM available? --> createEffect
During render, synchronous? --> createRenderEffect
Before render, state sync? --> createComputed
Need lifecycle hook?
YES --> Run once on mount? --> onMount
Cleanup on disposal? --> onCleanup
Need to control tracking?
YES --> Prevent tracking? --> untrack
Explicit deps only? --> on
Defer propagation? --> batch
Need external interop?
YES --> Signal to Observable? --> observable
Observable to Signal? --> from
Effect Execution Timing
| Aspect | createComputed | createRenderEffect | createEffect |
|---|
| When | Before render | During render (synchronous) | After render completes |
| Initial run | Before DOM exists | Before DOM mount | After DOM mount |
| Refs available | No | No (initial run) | Yes |
| Re-runs | Before render cycle | After memos, before paint | After render + memos |
| SSR behavior | Runs | Runs once (synchronous phase) | NEVER runs |
| Use case | State synchronization | DOM measurements | Side effects, subscriptions |
Core Primitives
createSignal
The foundational reactive atom. Returns a getter function and a setter function.
const [count, setCount] = createSignal<number>(0);
count();
setCount(5);
setCount((prev) => prev + 1);
const [data, setData] = createSignal<Data>(initial, {
equals: (prev, next) => prev.id === next.id,
name: "userData",
});
const [tick, setTick] = createSignal(0, { equals: false });
WRONG (React) vs CORRECT (SolidJS):
const [count, setCount] = useState(0);
return <div>{count}</div>;
const [count, setCount] = createSignal(0);
return <div>{count()}</div>;
createEffect
Runs side effects when tracked dependencies change. Dependencies are tracked automatically.
createEffect(() => {
document.title = `Count: ${count()}`;
});
createEffect((prev: number) => {
const current = count();
console.log("Changed from", prev, "to", current);
return current;
}, 0);
createEffect(() => {
const handler = () => console.log(count());
window.addEventListener("resize", handler);
onCleanup(() => window.removeEventListener("resize", handler));
});
WRONG (React) vs CORRECT (SolidJS):
useEffect(() => { console.log(count); }, [count]);
createEffect(() => { console.log(count()); });
useEffect(() => { return () => cleanup(); }, []);
createEffect(() => { onCleanup(() => cleanup()); });
createMemo
Cached derived value that IS a reactive source. Unlike React's useMemo, other computations can track a memo.
const double = createMemo(() => count() * 2);
createEffect(() => console.log(double()));
const filtered = createMemo(() =>
items().filter((item) => item.active)
);
WRONG (React) vs CORRECT (SolidJS):
createEffect(() => { setDouble(count() * 2); });
const double = createMemo(() => count() * 2);
createResource
Async data fetching with built-in loading/error states and Suspense integration.
const [data] = createResource(async () => {
const res = await fetch("/api/data");
return res.json();
});
const [userId, setUserId] = createSignal(1);
const [user] = createResource(userId, async (id) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
});
const [posts, { refetch, mutate }] = createResource(fetchPosts);
mutate((prev) => [...prev, newPost]);
await refetch();
<Suspense fallback={<Spinner />}>
<UserProfile />
</Suspense>
Resource states: data.state is one of "unresolved" | "pending" | "ready" | "refreshing" | "errored". Use data.loading, data.error, and data.latest for UI rendering.
Reactive Utilities
batch
Defers all downstream updates until the callback completes. Reduces m x n updates to m updates.
batch(() => {
setFirstName("John");
setLastName("Doe");
setAge(30);
});
ALWAYS remember: async breaks batching. Only updates before the first await are batched. Effects and store setters auto-batch internally.
untrack
Reads a signal without creating a dependency.
createEffect(() => {
console.log(count(), untrack(() => name()));
});
on
Explicitly specifies which dependencies to track. Use defer: true to skip the initial run.
createEffect(on(userId, (id, prevId) => {
console.log("User changed from", prevId, "to", id);
}, { defer: true }));
createEffect(on([a, b], ([aVal, bVal]) => {
console.log(aVal, bVal);
}));
Lifecycle
onMount / onCleanup
function Timer() {
let ref: HTMLDivElement;
onMount(() => {
ref.focus();
});
const timer = setInterval(() => tick(), 1000);
onCleanup(() => clearInterval(timer));
return <div ref={ref}>...</div>;
}
Reactive Anti-Patterns (React Contamination)
| React Pattern | Why It Breaks SolidJS | SolidJS Equivalent |
|---|
const { name } = props | Destructures once, kills tracking | props.name (access on object) |
const val = signal() at top level | Snapshot, never updates | Call signal() where needed |
useEffect(() => {}, [deps]) | No dependency arrays in SolidJS | createEffect(() => { }) |
useMemo(() => x, [deps]) | Not a reactive source | createMemo(() => x) |
useEffect(() => { return cleanup }) | Return value ignored | onCleanup(() => cleanup()) |
useEffect(() => {}, []) for mount | Wrong semantics | onMount(() => { }) |
| Early return before signal access | Skipped signals lose tracking | Access all signals first, then branch |
setState({...state, key: val}) | Full replacement, not granular | setStore("key", val) path syntax |
SolidJS 2.x Changes
| Feature | 1.x | 2.x |
|---|
| Reactivity | Synchronous | Microtask-batched (use flush() for immediate) |
| Effects | createEffect | Split compute/apply pattern |
| Mount hook | onMount | onSettled (can return cleanup) |
| Derived state | createMemo only | createSignal(fn) for derived-but-writable |
Reference Links
Official Sources