solid-development

SolidJS patterns, reactivity model, and best practices. Use when writing Solid components, reviewing Solid code, or debugging Solid issues.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "solid-development" with this command: npx skills add amorriscode/agent-grimoire/amorriscode-agent-grimoire-solid-development

Solid Development

Fine-grained reactivity patterns for SolidJS.

Instructions

SolidJS is NOT React. The mental model is fundamentally different:

ReactSolidJS
Components re-run on state changeComponents run once
Virtual DOM diffingDirect DOM updates
Hooks with dependency arraysAutomatic dependency tracking
useState returns valuecreateSignal returns getter function

1. Signals — Reactive Primitives

Signals are getter/setter pairs that track dependencies automatically:

import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);
  //     ^ getter (function!)  ^ setter

  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count()}  {/* Call the getter! */}
    </button>
  );
}

Rules:

  • Always call the getter: count() not count
  • The component function runs once — only the reactive parts update
  • Signals accessed in JSX are automatically tracked

2. Effects — Side Effects

Effects run when their tracked signals change:

import { createSignal, createEffect } from "solid-js";

function Logger() {
  const [count, setCount] = createSignal(0);

  // ✅ Tracked — runs when count changes
  createEffect(() => {
    console.log("Count is:", count());
  });

  // ❌ NOT tracked — runs once at setup
  console.log("Initial:", count());

  return <button onClick={() => setCount(c => c + 1)}>Increment</button>;
}

Key insight: Only signals accessed inside the effect are tracked.

3. Memos — Derived Values

Cache expensive computations:

import { createSignal, createMemo } from "solid-js";

function FilteredList() {
  const [items, setItems] = createSignal([]);
  const [filter, setFilter] = createSignal("");

  // Only recomputes when items or filter change
  const filtered = createMemo(() =>
    items().filter(item => item.includes(filter()))
  );

  return <For each={filtered()}>{item => <div>{item}</div>}</For>;
}

4. Props — Don't Destructure!

Critical: Destructuring props breaks reactivity.

// ❌ BROKEN — loses reactivity
function Greeting({ name }) {
  return <h1>Hello {name}</h1>;
}

// ❌ ALSO BROKEN
function Greeting(props) {
  const { name } = props;
  return <h1>Hello {name}</h1>;
}

// ✅ CORRECT — maintains reactivity
function Greeting(props) {
  return <h1>Hello {props.name}</h1>;
}

For defaults, use mergeProps:

import { mergeProps } from "solid-js";

function Button(props) {
  const merged = mergeProps({ variant: "primary" }, props);
  return <button class={merged.variant}>{merged.children}</button>;
}

For splitting props, use splitProps:

import { splitProps } from "solid-js";

function Input(props) {
  const [local, inputProps] = splitProps(props, ["label"]);
  return (
    <label>
      {local.label}
      <input {...inputProps} />
    </label>
  );
}

5. Control Flow Components

Don't use JS control flow in JSX — use Solid's components:

Conditionals with <Show>:

import { Show } from "solid-js";

<Show when={isLoggedIn()} fallback={<Login />}>
  <Dashboard />
</Show>

Multiple conditions with <Switch>/<Match>:

import { Switch, Match } from "solid-js";

<Switch>
  <Match when={status() === "loading"}>Loading...</Match>
  <Match when={status() === "error"}>Error!</Match>
  <Match when={status() === "success"}><Data /></Match>
</Switch>

Lists with <For>:

import { For } from "solid-js";

<For each={items()}>
  {(item, index) => <li>{index()}: {item.name}</li>}
</For>

<For> vs <Index>:

UseWhen
<For>List order/length changes (general case)
<Index>Fixed positions, content changes (performance optimization)

With <Index>, item is a signal: {(item, i) => <div>{item().name}</div>}

6. Stores — Complex State

Use stores for nested objects and shared state:

import { createStore } from "solid-js/store";

function TodoApp() {
  const [state, setState] = createStore({
    todos: [],
    filter: "all"
  });

  const addTodo = (text) => {
    setState("todos", todos => [...todos, { text, done: false }]);
  };

  const toggleTodo = (index) => {
    setState("todos", index, "done", done => !done);
  };

  return (/* ... */);
}

When to use:

  • Signals: Simple values, local state
  • Stores: Objects, arrays, shared state, nested data

7. Data Fetching with Resources

import { createResource, Suspense } from "solid-js";

function UserProfile(props) {
  const [user] = createResource(() => props.userId, fetchUser);

  return (
    <Suspense fallback={<Loading />}>
      <Show when={user()} fallback={<NotFound />}>
        <Profile user={user()} />
      </Show>
    </Suspense>
  );
}

Resource properties:

  • user() — the data (or undefined)
  • user.loading — boolean
  • user.error — error if failed
  • user.latest — last successful value

8. Context for Shared State

import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";

const AppContext = createContext();

function AppProvider(props) {
  const [state, setState] = createStore({ user: null, theme: "light" });
  return (
    <AppContext.Provider value={[state, setState]}>
      {props.children}
    </AppContext.Provider>
  );
}

function useApp() {
  return useContext(AppContext);
}

Common Mistakes

MistakeProblemFix
const { name } = propsBreaks reactivityAccess props.name directly
count instead of count()Gets function, not valueCall the signal getter
console.log(count()) outside effectOnly runs oncePut in createEffect
Using .map() for listsNo keyed updatesUse <For> component
Ternary in JSX for conditionalsWorks but less efficientUse <Show> component
Multiple signals for related dataVerbose, hard to manageUse createStore

Examples

Complete Component Pattern

import { createSignal, createMemo, createEffect, Show, For } from "solid-js";

function TaskList(props) {
  const [filter, setFilter] = createSignal("all");

  // Derived state
  const filteredTasks = createMemo(() => {
    const f = filter();
    if (f === "all") return props.tasks;
    return props.tasks.filter(t => (f === "done" ? t.done : !t.done));
  });

  // Side effect
  createEffect(() => {
    console.log(`Showing ${filteredTasks().length} tasks`);
  });

  return (
    <div>
      <select onChange={e => setFilter(e.target.value)}>
        <option value="all">All</option>
        <option value="done">Done</option>
        <option value="pending">Pending</option>
      </select>

      <Show when={filteredTasks().length > 0} fallback={<p>No tasks</p>}>
        <ul>
          <For each={filteredTasks()}>
            {task => (
              <li classList={{ done: task.done }}>
                {task.text}
              </li>
            )}
          </For>
        </ul>
      </Show>
    </div>
  );
}

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

react-development

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

Content Collector

个人内容收藏与知识管理系统。收藏、整理、检索、二创。 Use when: (1) 用户分享链接/文字/截图并要求保存或收藏, (2) 用户说"收藏这个"/"存一下"/"记录下来"/"save this"/"bookmark"/"clip this", (3) 用户要求按关键词/标签搜索之前收藏的内容, (4) 用...

Registry SourceRecently Updated