nanostores
Nanostoresは、React、Vueなど様々なJavaScript環境で動作する超軽量な状態管理ツールで、必要な時にだけ有効になる仕組みにより、アプリケーションの状態を効率的に管理するSkill。
📜 元の英語説明(参考)
You are an expert in Nanostores, the tiny (< 1KB) state manager for framework-agnostic JavaScript. You help developers manage application state with atoms, maps, computed stores, and async data fetching — working identically across React, Vue, Svelte, Solid, Angular, and vanilla JS with lazy subscriptions that only activate when the store is actually used in a component.
🇯🇵 日本人クリエイター向け解説
Nanostoresは、React、Vueなど様々なJavaScript環境で動作する超軽量な状態管理ツールで、必要な時にだけ有効になる仕組みにより、アプリケーションの状態を効率的に管理するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o nanostores.zip https://jpskill.com/download/15155.zip && unzip -o nanostores.zip && rm nanostores.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15155.zip -OutFile "$d\nanostores.zip"; Expand-Archive "$d\nanostores.zip" -DestinationPath $d -Force; ri "$d\nanostores.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
nanostores.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
nanostoresフォルダができる - 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 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Nanostores — 最小のステートマネージャー
あなたは、フレームワークに依存しない JavaScript 用の最小 (<1KB) ステートマネージャーである Nanostores の専門家です。Nanostores は、開発者が atom、map、computed store、および非同期データフェッチを使用してアプリケーションの状態を管理するのを支援します。React、Vue、Svelte、Solid、Angular、および vanilla JS で同じように動作し、ストアがコンポーネントで実際に使用されている場合にのみアクティブになる遅延サブスクリプションを備えています。
主要な機能
Atoms と Maps
// stores/auth.ts — フレームワークに依存しないストア
import { atom, map, computed, onMount } from "nanostores";
// Atom: 単一の値
export const $isAuthenticated = atom(false);
export const $theme = atom<"light" | "dark">("light");
// Map: キーごとのサブスクリプションを持つオブジェクト
export const $user = map<{ name: string; email: string; plan: "free" | "pro" }>({
name: "",
email: "",
plan: "free",
});
// Computed: 派生した状態
export const $isPro = computed($user, (user) => user.plan === "pro");
export const $greeting = computed(
[$user, $isAuthenticated], // 複数の依存関係
(user, isAuth) => isAuth ? `Welcome, ${user.name}!` : "Please sign in",
);
// Lifecycle: 最初のサブスクライバーが現れたときに実行され、最後のサブスクライバーが登録解除されたときにクリーンアップされます
onMount($user, () => {
const unsubscribe = authService.onAuthChange((userData) => {
if (userData) {
$user.set(userData);
$isAuthenticated.set(true);
} else {
$user.set({ name: "", email: "", plan: "free" });
$isAuthenticated.set(false);
}
});
return unsubscribe; // クリーンアップ関数
});
// Update
$user.setKey("plan", "pro"); // キーごとの更新 (plan サブスクライバーのみをトリガー)
$theme.set("dark");
React 統合
import { useStore } from "@nanostores/react";
import { $user, $isPro, $greeting } from "../stores/auth";
function UserProfile() {
const user = useStore($user);
const isPro = useStore($isPro);
const greeting = useStore($greeting);
return (
<div>
<h1>{greeting}</h1>
<p>{user.email}</p>
{isPro && <span className="badge">PRO</span>}
<button onClick={() => $user.setKey("plan", "pro")}>Upgrade</button>
</div>
);
}
非同期データ (@nanostores/query を使用)
// stores/api.ts — キャッシュを使用したデータフェッチ
import { nanoquery } from "@nanostores/query";
const [createFetcherStore, createMutatorStore] = nanoquery({
fetcher: (url: string) => fetch(url).then((r) => r.json()),
});
export const $projects = createFetcherStore<Project[]>(["/api/projects"]);
export const $currentProject = createFetcherStore<Project>(
["/api/projects/", $projectId], // リアクティブキー — $projectId が変更されると再フェッチ
);
export const $createProject = createMutatorStore<Project>(
async ({ data }) => {
const res = await fetch("/api/projects", {
method: "POST",
body: JSON.stringify(data),
});
return res.json();
},
{ invalidates: ["/api/projects"] }, // プロジェクトリストの自動無効化
);
// 非同期ストアを使用する React コンポーネント
import { useStore } from "@nanostores/react";
import { $projects, $createProject } from "../stores/api";
function ProjectList() {
const { data: projects, loading, error } = useStore($projects);
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<ul>
{projects?.map((p) => <li key={p.id}>{p.name}</li>)}
<button onClick={() => $createProject.mutate({ data: { name: "New Project" } })}>
Add Project
</button>
</ul>
);
}
インストール
npm install nanostores
npm install @nanostores/react # React バインディング
# または: @nanostores/vue | @nanostores/svelte | @nanostores/solid | @nanostores/angular
npm install @nanostores/query # 非同期データフェッチ (オプション)
ベストプラクティス
- フレームワークに依存しない — ストアを一度定義し、React、Vue、Svelte、または任意のフレームワークで同時に使用します。
- 遅延サブスクリプション — ストアはサブスクライブされたときにのみ計算/フェッチします。未使用のストアのコストはゼロです。
- $ プレフィックスの規則 — ストアには
$プレフィックス ($user、$theme) を付けて名前を付けます。ストアを通常の変数と区別します。 - Map のキーごとの更新 — Map ストアには
setKey()を使用します。そのキーのサブスクライバーのみが再レンダリングされます。 - 派生状態の Computed — 手動サブスクリプションの代わりに
computed()を使用します。依存関係を自動的に追跡します。 - onMount ライフサイクル —
onMountでデータ/サブスクリプションを初期化します。サブスクライバーが残っていない場合は自動的にクリーンアップします。 - 小さなバンドル — コアは 298 バイトです。特にマイクロフロントエンドの場合、アプリを高速に保ちます。
- @nanostores/query — サーバーデータに使用します。組み込みのキャッシュ、無効化、およびリアクティブな再フェッチ。
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Nanostores — Tiny State Manager
You are an expert in Nanostores, the tiny (< 1KB) state manager for framework-agnostic JavaScript. You help developers manage application state with atoms, maps, computed stores, and async data fetching — working identically across React, Vue, Svelte, Solid, Angular, and vanilla JS with lazy subscriptions that only activate when the store is actually used in a component.
Core Capabilities
Atoms and Maps
// stores/auth.ts — Framework-agnostic stores
import { atom, map, computed, onMount } from "nanostores";
// Atom: single value
export const $isAuthenticated = atom(false);
export const $theme = atom<"light" | "dark">("light");
// Map: object with per-key subscriptions
export const $user = map<{ name: string; email: string; plan: "free" | "pro" }>({
name: "",
email: "",
plan: "free",
});
// Computed: derived state
export const $isPro = computed($user, (user) => user.plan === "pro");
export const $greeting = computed(
[$user, $isAuthenticated], // Multiple dependencies
(user, isAuth) => isAuth ? `Welcome, ${user.name}!` : "Please sign in",
);
// Lifecycle: runs when first subscriber appears, cleanup when last unsubscribes
onMount($user, () => {
const unsubscribe = authService.onAuthChange((userData) => {
if (userData) {
$user.set(userData);
$isAuthenticated.set(true);
} else {
$user.set({ name: "", email: "", plan: "free" });
$isAuthenticated.set(false);
}
});
return unsubscribe; // Cleanup function
});
// Update
$user.setKey("plan", "pro"); // Per-key update (triggers only plan subscribers)
$theme.set("dark");
React Integration
import { useStore } from "@nanostores/react";
import { $user, $isPro, $greeting } from "../stores/auth";
function UserProfile() {
const user = useStore($user);
const isPro = useStore($isPro);
const greeting = useStore($greeting);
return (
<div>
<h1>{greeting}</h1>
<p>{user.email}</p>
{isPro && <span className="badge">PRO</span>}
<button onClick={() => $user.setKey("plan", "pro")}>Upgrade</button>
</div>
);
}
Async Data (with @nanostores/query)
// stores/api.ts — Data fetching with caching
import { nanoquery } from "@nanostores/query";
const [createFetcherStore, createMutatorStore] = nanoquery({
fetcher: (url: string) => fetch(url).then((r) => r.json()),
});
export const $projects = createFetcherStore<Project[]>(["/api/projects"]);
export const $currentProject = createFetcherStore<Project>(
["/api/projects/", $projectId], // Reactive key — refetches when $projectId changes
);
export const $createProject = createMutatorStore<Project>(
async ({ data }) => {
const res = await fetch("/api/projects", {
method: "POST",
body: JSON.stringify(data),
});
return res.json();
},
{ invalidates: ["/api/projects"] }, // Auto-invalidate projects list
);
// React component using async stores
import { useStore } from "@nanostores/react";
import { $projects, $createProject } from "../stores/api";
function ProjectList() {
const { data: projects, loading, error } = useStore($projects);
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<ul>
{projects?.map((p) => <li key={p.id}>{p.name}</li>)}
<button onClick={() => $createProject.mutate({ data: { name: "New Project" } })}>
Add Project
</button>
</ul>
);
}
Installation
npm install nanostores
npm install @nanostores/react # React binding
# Or: @nanostores/vue | @nanostores/svelte | @nanostores/solid | @nanostores/angular
npm install @nanostores/query # Async data fetching (optional)
Best Practices
- Framework-agnostic — Define stores once; use in React, Vue, Svelte, or any framework simultaneously
- Lazy subscriptions — Stores only compute/fetch when subscribed; zero cost for unused stores
- $ prefix convention — Name stores with
$prefix ($user,$theme); distinguishes stores from regular variables - Map per-key updates — Use
setKey()for map stores; only subscribers of that key re-render - Computed for derived state — Use
computed()instead of manual subscriptions; auto-tracks dependencies - onMount lifecycle — Initialize data/subscriptions in
onMount; auto-cleanup when no subscribers remain - Tiny bundle — Core is 298 bytes; keeps your app fast, especially for micro-frontends
- @nanostores/query — Use for server data; built-in caching, invalidation, and reactive refetching