Install
$ agentstack add skill-impertio-studio-solidjs-claude-skill-package-solid-core-reactivity-model ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
solid-core-reactivity-model
Quick Reference
The Fundamental Mental Model
SolidJS has NO virtual DOM. Components run exactly once to set up a reactive dependency graph. Only reactive expressions (effects, memos, JSX bindings) re-execute when their dependencies change. The DOM is updated directly through reactive bindings — no diffing, no reconciliation, no re-rendering.
Tracking Scope Matrix
| Context | Tracking? | Re-executes on change? | Purpose | |---------|-----------|----------------------|---------| | createEffect(() => ...) | YES | YES | Side effects | | createMemo(() => ...) | YES | YES | Cached derived values | | createRenderEffect(() => ...) | YES | YES | Synchronous render-phase effects | | createComputed(() => ...) | YES | YES | Pre-render state sync | | JSX expression {count()} | YES | YES | DOM text/attribute bindings | | Component function body | NO | NO — runs once | Setup only | | Event handlers onClick | NO | NO — runs on demand | User interaction | | onMount(() => ...) | NO | NO — runs once after mount | DOM initialization | | untrack(() => ...) | NO | NO — explicitly suppressed | Read without subscribing |
Reactive Dependency Graph
Signal (source) Memo (derived) Effect (sink)
[count] ──────────► [double] ──────────► [DOM update]
│ ▲
└──────────────────────────────────────────────┘
(direct subscription)
- Signals are sources — they store values and notify subscribers
- Memos are derived nodes — they cache computed values and propagate changes
- Effects are sinks — they perform side effects, NEVER produce reactive values
- Dependencies are tracked automatically when a signal/memo getter is called inside a tracking scope
Execution Models
| Aspect | SolidJS 1.x | SolidJS 2.x | |--------|-------------|-------------| | Signal propagation | Synchronous — updates propagate immediately | Microtask-batched — reads reflect after flush | | Forcing immediate propagation | N/A (already synchronous) | flush() | | Effect timing | After render, before paint | Compute-then-apply split | | Lifecycle hook | onMount | onSettled (can return cleanup) | | Async support | Manual via createResource | First-class — computations can return Promises |
Critical Warnings
NEVER assume components re-render — SolidJS component functions run ONCE. Only reactive expressions inside tracking scopes re-execute. Placing logic in the component body expecting it to re-run is the #1 cause of broken SolidJS code.
NEVER destructure props or signal results outside a tracking scope — this captures a static snapshot and permanently breaks reactivity.
NEVER use dependency arrays — SolidJS tracks dependencies automatically. There is no equivalent to React's useEffect([deps]) or useMemo([deps]).
NEVER return cleanup functions from effects — use onCleanup() as a separate call instead. Returning a function from createEffect does NOT register cleanup.
NEVER access signals conditionally or after early returns inside effects — signals accessed after an early return or inside an if branch are only tracked when that code path executes, causing intermittent tracking failures.
ALWAYS call signal getters as functions (count(), not count) — the getter function call is what registers the dependency in the tracking scope.
ALWAYS access props directly (props.name) or use splitProps/mergeProps — NEVER destructure props at the function parameter level.
How JSX Compilation Works
SolidJS compiles JSX into direct DOM creation calls with reactive bindings. There is no virtual DOM tree, no diff algorithm, no reconciliation.
// What you write:
const el = {count()};
// What the compiler produces (conceptual):
const el = document.createElement("div");
createRenderEffect(() => el.className = className());
createRenderEffect(() => el.textContent = count());
Each {expression} in JSX becomes a fine-grained reactive binding. When count() changes, ONLY that specific text node updates — the div element, its attributes, and all sibling nodes remain untouched.
Ownership Tree and Disposal
SolidJS organizes reactive computations into an ownership tree. Every computation (effect, memo) is owned by the scope that created it. When a scope disposes, all child computations are automatically cleaned up.
Key Primitives
| Primitive | Purpose | |-----------|---------| | createRoot(fn) | Creates a new ownership root — computations inside are NOT auto-disposed | | getOwner() | Returns the current tracking owner (or null outside any scope) | | runWithOwner(owner, fn) | Executes fn under a specific owner's scope | | onCleanup(fn) | Registers cleanup for when the current scope disposes or re-executes |
Ownership Hierarchy
createRoot (application root)
└── Component A (runs once)
├── createEffect (owned by A)
│ └── onCleanup (runs on re-execute or dispose)
├── createMemo (owned by A)
└── Child Component B (owned by A)
└── createEffect (owned by B)
When Component A unmounts, ALL its owned computations (effects, memos, child components) are disposed automatically.
When to Use createRoot
ALWAYS use createRoot when creating reactive computations outside of a component tree — for example, in a standalone reactive system, a test harness, or a module-level subscription.
// WRONG: Effect created outside ownership — memory leak, no cleanup
createEffect(() => console.log(globalSignal()));
// CORRECT: createRoot provides ownership and disposal
const dispose = createRoot((dispose) => {
createEffect(() => console.log(globalSignal()));
return dispose;
});
// Later: dispose() to clean up
runWithOwner for Async Contexts
Async callbacks lose their tracking owner. Use runWithOwner to restore it:
function AsyncComponent() {
const owner = getOwner();
onMount(async () => {
const data = await fetchData();
// WRONG: createEffect here has no owner (async broke the scope)
// CORRECT: restore the owner explicitly
runWithOwner(owner!, () => {
createEffect(() => console.log(data, someSignal()));
});
});
}
Synchronous vs Batched Execution
SolidJS 1.x: Synchronous by Default
Signal updates propagate immediately. Each setSignal() call triggers all dependent computations synchronously before the next line of code executes.
const [a, setA] = createSignal(1);
const [b, setB] = createSignal(2);
createEffect(() => console.log(a() + b()));
setA(10); // Effect runs immediately: logs 12
setB(20); // Effect runs immediately: logs 30
Use batch() to defer propagation:
batch(() => {
setA(10);
setB(20);
}); // Effect runs ONCE: logs 30
SolidJS 2.x: Microtask-Batched by Default
All signal updates are batched automatically. Reads do NOT reflect updates until the microtask batch flushes. Use flush() when immediate propagation is needed.
// 2.x behavior:
setA(10);
setB(20);
// Effects have NOT run yet — batched until microtask flush
flush(); // Force immediate propagation
Version-Specific Changes
Key 2.x Reactivity Changes
- Microtask batching: Default behavior — no manual
batch()needed for most cases flush(): Forces immediate propagation when synchronous behavior is required- Async first-class: Computations can return Promises; the graph handles suspension automatically
onMountrenamed toonSettled: Can return a cleanup function- Dev guardrails: Warnings for accidental top-level reads and reactive scope writes
createSignal(fn): Derived-but-writable signals (function argument creates derived initial value)
Decision Trees
"Should this code be in a tracking scope?"
- Does the code read a signal/memo value? → If NO → tracking scope not needed
- Should the code re-run when that value changes? → If NO → use
untrack()or read in component body - Does the code produce a derived value? → If YES → use
createMemo - Does the code perform a side effect? → If YES → use
createEffect - Does the code update the DOM directly? → If YES → use
createRenderEffect
"Why is my value not updating?"
- Are you calling the signal getter as a function? →
count()notcount - Is the access inside a tracking scope? → Component body is NOT tracked
- Did you destructure props or store values? → Destructuring breaks tracking
- Is there an early return BEFORE the signal access? → Move signal reads before returns
- Is the access inside
untrack()? → This explicitly suppresses tracking - Is the signal inside a conditional branch? → Access unconditionally, use value conditionally
Reference Links
- [references/methods.md](references/methods.md) — API signatures for createRoot, getOwner, runWithOwner, tracking scope primitives
- [references/examples.md](references/examples.md) — Reactive graph examples, tracking demos, ownership patterns
- [references/anti-patterns.md](references/anti-patterns.md) — React mental model violations: re-render assumption, VDOM thinking, dependency arrays
Official Sources
- https://docs.solidjs.com/concepts/intro-to-reactivity
- https://docs.solidjs.com/concepts/signals
- https://docs.solidjs.com/concepts/effects
- https://docs.solidjs.com/reference/basic-reactivity/create-signal
- https://docs.solidjs.com/reference/basic-reactivity/create-effect
- https://docs.solidjs.com/reference/basic-reactivity/create-memo
- https://docs.solidjs.com/reference/reactive-utilities/batch
- https://docs.solidjs.com/reference/reactive-utilities/untrack
- https://github.com/solidjs/solid/releases
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Impertio-Studio
- Source: Impertio-Studio/SolidJS-Claude-Skill-Package
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.