agentsclimarketplace

Solid expert

Skill Akayashuu/agent-skills/skills/solid-expert

Use when writing, reviewing, or debugging SolidJS — using createSignal/createMemo/createEffect, fine-grained reactivity, stores, props, or when reactivity silently stops updating.From its SKILL.md

Install
npx -y skills add Akayashuu/agent-skills --skill solid-expert

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

6.4 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

SolidJS Expert

Overview

The #1 trap is treating Solid like React. Components run ONCE. There is no re-render, no virtual DOM, no dependency arrays. Reactivity is fine-grained: reading a signal inside a tracking scope (JSX, createMemo, createEffect) subscribes that exact spot, and only that spot updates. Most "Solid isn't updating" bugs come from breaking the subscription — destructuring props or reading a signal in code that runs once.

Quick Reference

GoalDoAvoid
Read a signalcall it: count()count (that's the getter, not the value)
Use propsprops.x lazily, or splitProps/mergePropsdestructuring { x } (kills reactivity)
Derived/expensive valuecreateMemo(() => …)recompute inline every read
Side effectcreateEffect (runs after render, tracks deps)doing effects in component body
Render a list<For each={items()}>items().map(...)
Conditional<Show when={ok()}>{ok() && …} ternary in once-run code
Nested reactive statecreateStore + path settersa signal holding a big object
Explicit dependencieson(dep, handler)relying on implicit tracking
Opt out of trackinguntrack(() => …)reading then ignoring
Async datacreateResource(source, fetcher)manual fetch in createEffect

Core Patterns

Don't destructure props — it snapshots the value once and breaks reactivity:

// ❌ name is read once at call time; later updates never reach the DOM
function Hello({ name }: { name: string }) {
  return <h1>Hello {name}</h1>
}
// ✅ access lazily, or splitProps to keep reactive proxies intact
function Hello(props: { name: string; class?: string }) {
  const [local, rest] = splitProps(props, ['name'])
  return <h1 {...rest}>Hello {local.name}</h1> // re-reads on change
}

Signals are getters — call them, and call them inside a tracking scope:

// ❌ destructured + read once in body; the <p> never updates
function Counter() {
  const [count] = createSignal(0)
  const doubled = count() * 2          // runs once, frozen
  return <p>{doubled}</p>
}
// ✅ read inside JSX (a tracking scope) or a memo — see runnable example

Runnable: examples/counter.tsx

<For> over .map() — keyed by reference, rows persist instead of re-creating:

// ❌ .map() is evaluated once; the list never re-renders on change
<ul>{users().map(u => <li>{u.name}</li>)}</ul>
// ✅ <For> diffs by reference (use <Index> when keyed by position instead)
<For each={users()}>{(u) => <li>{u.name}</li>}</For>

<For> is keyed by item identity (reorders move DOM nodes); <Index> is keyed by position (the item is a signal () => T) — use it for primitives or fixed-length lists.

createStore for nested objects — fine-grained, only touched paths update:

setState('user', 'name', 'Grace')              // path setter, surgical
setState('user', 'tags', produce(t => t.push('b'))) // mutate-style via produce

Runnable: examples/store-nested.ts

createResource for async — the idiomatic data fetch, not fetch in an effect:

// source is a signal/accessor; when it changes (and isn't false/null/undefined)
// the fetcher re-runs. Returns [resource, { mutate, refetch }].
const [user] = createResource(userId, (id) => fetch(`/u/${id}`).then(r => r.json()))
// user() is the data; .loading / .error are reactive

Runnable: examples/resource-fetch.tsx

mutate(v) writes optimistically; refetch() reloads. Pairs with <Suspense> and <ErrorBoundary>.

Common Mistakes

  • Destructuring props — the canonical Solid bug. Keep props whole; use mergeProps for defaults, splitProps to forward.
  • Reading a signal without calling it — {count} renders the function, never updates. It's {count()}.
  • .map()/ternary instead of <For>/<Show> — runs once, won't react. Control-flow components subscribe.
  • Expecting the component body to re-run — it runs once. Put reactive reads in JSX, createMemo, or createEffect.
  • Effects to compute values — use createMemo. Reserve createEffect for genuine side effects (DOM, logging, fetch).
  • createEffect writing a signal it reads — infinite loops; reach for on() with defer, or untrack. Batch grouped writes with batch.

When NOT to over-engineer

createMemo has bookkeeping cost — don't wrap cheap expressions (a() + b()); only memo expensive work or values feeding many subscribers. A plain () => … derived accessor is often enough. Use createStore for genuinely nested state; a single signal is fine for flat values. Reach for on()/untrack/batch only when implicit tracking actually misbehaves, not preemptively.

Reusable primitives

primitives.ts (same dir) — typed, SSR-safe createPersistedSignal (localStorage-backed signal, cross-tab sync) and createEventListener (auto-cleaned binding). Both use onCleanup so listeners die with their owner; copy/adapt rather than re-deriving the lifecycle each time.

Version note

Stable is Solid 1.9.x (everything above targets it). Solid 2.0 is in beta (solid-js@next): async becomes first-class (computations/createMemo can return Promises, reworked <Suspense>, deterministic batching). The 1.9 mental model — components run once, signals are getters, don't destructure props — carries forward; don't adopt 2.0 APIs in production yet.

Sources

What ships with it: 4 files

4.5 KB alongside SKILL.md, 2 of them executable

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.