web-framework-solidjs
SolidJSのきめ細かいリアクティビティパターン(シグナル、エフェクト、メモ、ストア、リソース作成、制御フロー、Suspense、SolidStartなど)を活用して、効率的なWebアプリケーション開発を支援するSkill。
📜 元の英語説明(参考)
SolidJS fine-grained reactivity patterns - signals, effects, memos, stores, createResource, control flow components, Suspense, SolidStart
🇯🇵 日本人クリエイター向け解説
SolidJSのきめ細かいリアクティビティパターン(シグナル、エフェクト、メモ、ストア、リソース作成、制御フロー、Suspense、SolidStartなど)を活用して、効率的なWebアプリケーション開発を支援するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o web-framework-solidjs.zip https://jpskill.com/download/10284.zip && unzip -o web-framework-solidjs.zip && rm web-framework-solidjs.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10284.zip -OutFile "$d\web-framework-solidjs.zip"; Expand-Archive "$d\web-framework-solidjs.zip" -DestinationPath $d -Force; ri "$d\web-framework-solidjs.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
web-framework-solidjs.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
web-framework-solidjsフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
SolidJS のパターン
クイックガイド: プリミティブには
createSignal、ネストされたオブジェクトにはcreateStoreを使用します。常にシグナルを関数として呼び出してください (countではなくcount())。決して props を分割代入しないでください。制御フローには<Show>、<For>、<Switch>を使用します。非同期データはcreateResourceで、コンポーネントは<Suspense>でラップします。
<critical_requirements>
重要: この Skill を使用する前に
すべてのコードは
CLAUDE.mdのプロジェクト規約に従う必要があります (kebab-case、名前付きエクスポート、インポート順序、import type、名前付き定数)
(値を読み取るには、必ずシグナルを関数として呼び出す必要があります - count ではなく count())
(リアクティビティを維持するために、決して props を分割代入しないでください - props.name または splitProps() を使用してください)
(三項演算子や .map() の代わりに、必ず <Show>、<For>、<Switch> 制御フローコンポーネントを使用してください)
(エフェクト内で onCleanup() を使用して、副作用を必ずクリーンアップしてください)
(非同期データフェッチは createResource で、コンポーネントは <Suspense> で必ずラップしてください)
</critical_requirements>
自動検出: SolidJS, createSignal, createEffect, createMemo, createStore, createResource, createAsync, query, action, Show, For, Switch, Match, splitProps, mergeProps, onCleanup, onMount, Suspense, ErrorBoundary, solid-js, @solidjs/router, SolidStart
いつ使うか:
- きめ細かいリアクティビティ (仮想 DOM なし) を持つリアクティブ UI を構築する場合
- シグナル (プリミティブ) とストア (ネストされたオブジェクト) で状態を管理する場合
- メモで派生値を生成する場合
- createResource で非同期データをフェッチする場合
- SolidStart でフルスタックアプリを構築する場合
カバーする主なパターン:
- シグナル、エフェクト、メモ (コアリアクティビティ)
- コンポーネントパターン (props, splitProps, mergeProps, refs)
- 制御フローコンポーネント (Show, For, Index, Switch, Match)
- 複雑なネストされた状態のためのストア
- 非同期データフェッチのための createResource (プレーンな SolidJS)
- データフェッチのための createAsync + query (SolidStart, Solid 2.0 で推奨)
- 依存性注入のためのコンテキスト
- 非同期処理のための Suspense と ErrorBoundary
- SolidStart パターン (サーバー関数、query、actions)
いつ使わないか:
- チームが React エコシステムに深く投資している場合
- 広範なサードパーティ React コンポーネントライブラリを必要とするプロジェクト
- React 固有の機能 (Server Components、concurrent mode) が必要な場合
詳細なリソース:
- examples/core.md - シグナル、エフェクト、メモ、バッチ
- examples/components.md - Props 処理、制御フロー、refs、コンポーネントタイプ
- examples/stores.md - createStore, produce, reconcile, Context
- examples/resources.md - createResource, createAsync, query/action (SolidStart)
- reference.md - 意思決定フレームワーク、アンチパターン、チェックリスト
<philosophy>
哲学
SolidJS は、きめ細かいリアクティビティを通じて卓越したパフォーマンスを実現します。React のようにコンポーネントツリー全体を再レンダリングする代わりに、Solid は式レベルで依存関係を追跡し、変更された特定の DOM ノードのみを外科的に更新します。コンポーネントは、状態が変化するたびにではなく、作成時に一度だけ実行されます。
コア原則:
- きめ細かいリアクティビティ - 更新はコンポーネントレベルではなく、DOM ノードレベルで発生します
- シグナルは関数である - シグナルを読み取る (
count()) ことで、それにサブスクライブし、自動的な依存関係追跡を作成します - コンポーネントは一度だけ実行される - コンポーネント関数本体は、作成時にのみ実行されます
- 仮想 DOM はない - 直接 DOM 操作により、差分計算のオーバーヘッドがなくなります
- 明示的なリアクティビティ - 状態は
createSignalとcreateStoreを介して明示的にリアクティブになります
重要なメンタルモデル:
// React: コンポーネントが再レンダリングされ、すべてが再計算されます
function Counter() {
const [count, setCount] = useState(0);
console.log('これはすべての更新で実行されます'); // 再実行
return <span>{count}</span>; // span を再レンダリング
}
// Solid: コンポーネントは一度だけ実行され、式のみが更新されます
function Counter() {
const [count, setCount] = createSignal(0);
console.log('これは一度だけ実行されます'); // 作成時のみ
return <span>{count()}</span>; // テキストノードのみが更新されます
}
</philosophy>
<patterns>
コアパターン
パターン 1: シグナル - リアクティブプリミティブ
シグナルは、Solid のリアクティビティの基礎です。値を保持し、変更時にサブスクライバーに通知します。
基本的なシグナル
import { createSignal } from "solid-js";
const MAX_COUNT = 100;
const INITIAL_COUNT = 0;
// createSignal は [getter, setter] を返します
const [count, setCount] = createSignal(INITIAL_COUNT);
// 読み取るには関数として呼び出す必要があります
console.log(count()); // 0
// 値の設定
setCount(5);
setCount((prev) => prev + 1); // 関数型アップデート
// TypeScript で明示的な型を使用する
const [user, setUser] = createSignal<User | null>(null);
良い点: 関数呼び出しによる明示的なリアクティビティ、自動依存関係追跡、ジェネリクスによる型安全性、関数型アップデートによる古いクロージャバグの防止
コンポーネント内のシグナル
import { createSignal, type Component } from 'solid-js';
const Counter: Component = () => {
const [count, setCount] = createSignal(0);
// この console.log は一度だけ実行され、更新ごとには実行されません
console.log('コンポーネントが作成されました');
return (
<div>
{/* count が変更されると、このテキストノードのみが更新されます */}
<span>カウント: {count()}</span>
<button onClick={() => setCount(c => c + 1)}>インクリメント</button>
</div>
);
};
export { Counter };
良い点: コンポーネント本体は一度だけ実行され、{count()} 式のみが更新時に再評価され、DOM 操作が最小限に抑えられます
パターン 2: エフェクト - 状態変化時の副作用
エフェクトは、追跡された依存関係が変化すると自動的に実行されます。
createEffect
import { createSignal, createEffect, onCleanup } from "solid-js";
const [count, setCount] = createSignal(0);
// count() を依存関係として自動的に追跡します
createEffect(() => {
console.log("カウントが変更されました:", count());
});
// クリーンアップ付きのエフェクト
createEffect(() => {
const handler = () => console. 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
SolidJS Patterns
Quick Guide: Use
createSignalfor primitives,createStorefor nested objects. Always call signals as functions (count()notcount). Never destructure props. Use<Show>,<For>,<Switch>for control flow. Wrap async data increateResourceand components in<Suspense>.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST call signals as functions to read values - count() NOT count)
(You MUST NEVER destructure props - use props.name or splitProps() to preserve reactivity)
(You MUST use <Show>, <For>, <Switch> control flow components instead of ternaries and .map())
(You MUST clean up side effects with onCleanup() inside effects)
(You MUST wrap async data fetching in createResource and components in <Suspense>)
</critical_requirements>
Auto-detection: SolidJS, createSignal, createEffect, createMemo, createStore, createResource, createAsync, query, action, Show, For, Switch, Match, splitProps, mergeProps, onCleanup, onMount, Suspense, ErrorBoundary, solid-js, @solidjs/router, SolidStart
When to use:
- Building reactive UIs with fine-grained reactivity (no virtual DOM)
- Managing state with signals (primitives) and stores (nested objects)
- Creating derived values with memos
- Fetching async data with createResource
- Building full-stack apps with SolidStart
Key patterns covered:
- Signals, effects, and memos (core reactivity)
- Component patterns (props, splitProps, mergeProps, refs)
- Control flow components (Show, For, Index, Switch, Match)
- Stores for complex nested state
- createResource for async data fetching (plain SolidJS)
- createAsync + query for data fetching (SolidStart, recommended for Solid 2.0)
- Context for dependency injection
- Suspense and ErrorBoundary for async handling
- SolidStart patterns (server functions, query, actions)
When NOT to use:
- When team is deeply invested in React ecosystem
- Projects requiring extensive third-party React component libraries
- When you need React-specific features (Server Components, concurrent mode)
Detailed Resources:
- examples/core.md - Signals, effects, memos, batch
- examples/components.md - Props handling, control flow, refs, component types
- examples/stores.md - createStore, produce, reconcile, Context
- examples/resources.md - createResource, createAsync, query/action (SolidStart)
- reference.md - Decision frameworks, anti-patterns, checklists
<philosophy>
Philosophy
SolidJS achieves exceptional performance through fine-grained reactivity: instead of re-rendering entire component trees like React, Solid tracks dependencies at the expression level and surgically updates only the specific DOM nodes that changed. Components run once during creation, not on every state change.
Core principles:
- Fine-grained reactivity - Updates happen at the DOM node level, not component level
- Signals are functions - Reading a signal (
count()) subscribes to it, creating automatic dependency tracking - Components run once - The component function body executes only at creation time
- No virtual DOM - Direct DOM manipulation eliminates diffing overhead
- Explicit reactivity - State is explicitly reactive via
createSignalandcreateStore
Key mental model:
// React: Component re-renders, recalculates everything
function Counter() {
const [count, setCount] = useState(0);
console.log('This runs on EVERY update'); // Re-runs
return <span>{count}</span>; // Re-renders span
}
// Solid: Component runs once, only expressions update
function Counter() {
const [count, setCount] = createSignal(0);
console.log('This runs ONCE'); // Only at creation
return <span>{count()}</span>; // Only text node updates
}
</philosophy>
<patterns>
Core Patterns
Pattern 1: Signals - Reactive Primitives
Signals are the foundation of Solid's reactivity. They hold a value and notify subscribers when it changes.
Basic Signals
import { createSignal } from "solid-js";
const MAX_COUNT = 100;
const INITIAL_COUNT = 0;
// createSignal returns [getter, setter]
const [count, setCount] = createSignal(INITIAL_COUNT);
// MUST call as function to read
console.log(count()); // 0
// Setting values
setCount(5);
setCount((prev) => prev + 1); // Functional update
// With TypeScript explicit types
const [user, setUser] = createSignal<User | null>(null);
Why good: Explicit reactivity through function calls, automatic dependency tracking, type-safe with generics, functional updates prevent stale closure bugs
Signals in Components
import { createSignal, type Component } from 'solid-js';
const Counter: Component = () => {
const [count, setCount] = createSignal(0);
// This console.log runs ONCE, not on every update
console.log('Component created');
return (
<div>
{/* Only this text node updates when count changes */}
<span>Count: {count()}</span>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
};
export { Counter };
Why good: Component body runs once, only {count()} expression re-evaluates on update, minimal DOM manipulation
Pattern 2: Effects - Side Effects on State Changes
Effects run automatically when their tracked dependencies change.
createEffect
import { createSignal, createEffect, onCleanup } from "solid-js";
const [count, setCount] = createSignal(0);
// Automatically tracks count() as dependency
createEffect(() => {
console.log("Count changed:", count());
});
// Effect with cleanup
createEffect(() => {
const handler = () => console.log("Clicked, count:", count());
window.addEventListener("click", handler);
// MUST clean up to prevent memory leaks
onCleanup(() => {
window.removeEventListener("click", handler);
});
});
Why good: Automatic dependency tracking (no dependency array), onCleanup runs before each re-execution and on disposal
Explicit Tracking with on()
import { createSignal, createEffect, on } from "solid-js";
const [count, setCount] = createSignal(0);
const [name, setName] = createSignal("");
// Only tracks count, ignores name even if accessed
createEffect(
on(count, (value, prev) => {
console.log("Count went from", prev, "to", value);
// name() here won't add a dependency
console.log("Current name:", name());
}),
);
// Multiple explicit dependencies
createEffect(
on([count, name], ([c, n]) => {
console.log("Either changed:", c, n);
}),
);
Why good: Explicit control over what triggers the effect, access to previous value
Pattern 3: Memos - Cached Derived Values
Memos cache computed values and only recalculate when dependencies change.
createMemo
import { createSignal, createMemo } from "solid-js";
const [items, setItems] = createSignal<Item[]>([]);
const [filter, setFilter] = createSignal("");
// Only recalculates when items or filter changes
const filteredItems = createMemo(() => {
console.log("Filtering..."); // Only runs when dependencies change
return items().filter((item) =>
item.name.toLowerCase().includes(filter().toLowerCase()),
);
});
// Expensive computation - memoized automatically
const sortedItems = createMemo(() => {
return [...items()].sort((a, b) => a.name.localeCompare(b.name));
});
Why good: Caches result until dependencies change, prevents unnecessary recalculations, clearer than inline expressions for complex logic
Pattern 4: Component Props
Never destructure props in Solid - it breaks reactivity.
Props with splitProps and mergeProps
import { splitProps, mergeProps, type Component, type JSX } from 'solid-js';
interface ButtonProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary';
loading?: boolean;
}
const Button: Component<ButtonProps> = (rawProps) => {
// Default props with mergeProps
const props = mergeProps({ variant: 'primary' as const }, rawProps);
// Split custom props from native HTML attributes
const [local, buttonProps] = splitProps(props, ['variant', 'loading']);
return (
<button
{...buttonProps}
class={`btn btn-${local.variant}`}
disabled={local.loading || buttonProps.disabled}
>
{local.loading ? 'Loading...' : props.children}
</button>
);
};
export { Button };
Why good: splitProps separates custom props from spread-able HTML props, mergeProps provides defaults while preserving reactivity, never destructure props
Component Types
Use VoidComponent (no children), ParentComponent (children required), or Component (children optional) for type-safe children handling.
const Icon: VoidComponent<{ name: string }> = (props) => (/* ... */);
const Card: ParentComponent<{ title: string }> = (props) => (/* ... */);
See examples/components.md for full component type examples.
Pattern 5: Control Flow Components
Solid uses dedicated components for control flow instead of JavaScript expressions.
Show for Conditionals
import { Show } from 'solid-js';
// Basic condition with fallback
<Show when={user()} fallback={<LoginForm />}>
<Dashboard />
</Show>
// Keyed flow - access the truthy value safely
<Show when={user()} fallback={<LoginForm />}>
{(user) => <Dashboard user={user()} />}
</Show>
Why good: Optimized for fine-grained updates, keyed flow provides narrowed type
For for Lists
import { For } from 'solid-js';
// Basic list rendering
<For each={items()} fallback={<p>No items</p>}>
{(item, index) => (
<li>
{index()}: {item.name}
</li>
)}
</For>
Why good: Automatically handles keying by reference, index() is a signal, optimized list diffing
Switch/Match for Multiple Conditions
import { Switch, Match } from 'solid-js';
<Switch fallback={<p>Unknown status</p>}>
<Match when={status() === 'loading'}>
<Spinner />
</Match>
<Match when={status() === 'error'}>
<ErrorMessage error={error()} />
</Match>
<Match when={status() === 'success'}>
<SuccessView data={data()} />
</Match>
</Switch>
Why good: First matching condition renders, cleaner than nested Shows
Pattern 6: Refs
Refs work differently in Solid - no forwardRef needed.
DOM and Component Refs
import { onMount, type Component } from 'solid-js';
const Form: Component = () => {
let inputRef: HTMLInputElement;
onMount(() => {
// Ref is available after mount
inputRef.focus();
});
return (
<form>
{/* Ref callback or assignment */}
<input ref={inputRef!} type="text" />
<input ref={(el) => console.log('Element:', el)} type="email" />
</form>
);
};
export { Form };
Why good: No forwardRef wrapper needed, refs are just props, works with components and DOM elements
Pattern 7: Context
Share data across component tree without prop drilling. Create a typed context, wrap in Provider with a Store, and expose a hook with error handling.
const AuthContext = createContext<AuthContextValue>();
const AuthProvider: ParentComponent = (props) => {
const [store, setStore] = createStore<{ user: User | null }>({ user: null });
const value = { get user() { return store.user; }, /* actions */ };
return <AuthContext.Provider value={value}>{props.children}</AuthContext.Provider>;
};
function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within AuthProvider');
return ctx;
}
Why good: Getter on store field preserves reactivity in context, throws on missing provider
See examples/stores.md for complete Store + Context implementation.
</patterns>
<integration>
Integration Guide
SolidJS is framework-agnostic for styling and tooling. Components receive props and emit events, fitting any styling or state management approach.
Ecosystem:
- SolidStart for full-stack applications with file-based routing
- @solidjs/router for client-side routing
- solid-primitives community library for common utilities
- Any CSS solution via
classattribute binding
State decisions:
- Simple values:
createSignal - Nested objects/arrays:
createStore - Shared across components: Context + Store
- Async data:
createResourceorcreateAsync(SolidStart)
Component communication:
- Props down, callbacks up (like React)
- Context for deeply nested sharing
- No prop drilling thanks to fine-grained reactivity
</integration>
<red_flags>
RED FLAGS
- Reading signal without parentheses -
countinstead ofcount()doesn't read the value or track dependencies - Destructuring props -
const { name } = propsbreaks reactivity; useprops.nameorsplitProps() - Using ternary instead of Show -
{condition ? <A /> : <B />}bypasses Solid's optimizations - Using .map() instead of For -
{items().map(...)}doesn't get fine-grained list updates - Missing onCleanup in effects - Event listeners, timers, subscriptions will leak memory
- Async operations inside createEffect tracking scope - Code after
awaitloses tracking context - Side effects in createMemo - Memos should be pure; use createEffect for side effects
- Using createEffect for data fetching - Use createResource or createAsync instead
- Direct mutation of store -
store.field = xbypasses proxy tracking; use setStore path syntax
Gotchas:
- Signals read outside reactive context (event handlers) aren't tracked
- Stores only track property access (
store.field), not the store object itself - Code after
awaitin effects runs outside the tracking scope childrenis a getter in Solid - usechildren()helper when iterating- Index provides values as signals - call
item()inside Index, not in For
See reference.md for full anti-pattern examples and decision frameworks.
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST call signals as functions to read values - count() NOT count)
(You MUST NEVER destructure props - use props.name or splitProps() to preserve reactivity)
(You MUST use <Show>, <For>, <Switch> control flow components instead of ternaries and .map())
(You MUST clean up side effects with onCleanup() inside effects)
(You MUST wrap async data fetching in createResource and components in <Suspense>)
Failure to follow these rules will break reactivity, cause memory leaks, or result in stale UI.
</critical_reminders>