jpskill.com
🛠️ 開発・MCP コミュニティ

valtio

Valtioは、Reactの状態管理を簡単にするライブラリで、複雑な設定なしにプロキシベースの状態管理を実現し、ZustandやReduxの代替として、より手軽に状態管理をしたい場合に役立つSkill。

📜 元の英語説明(参考)

Manage React state with Valtio — proxy-based state that just works. Use when someone asks to "simple React state management", "Valtio", "proxy state", "mutable state in React", "alternative to Zustand/Redux", or "state management without boilerplate". Covers proxy state, subscriptions, computed values, and devtools.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Valtioは、Reactの状態管理を簡単にするライブラリで、複雑な設定なしにプロキシベースの状態管理を実現し、ZustandやReduxの代替として、より手軽に状態管理をしたい場合に役立つSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o valtio.zip https://jpskill.com/download/15531.zip && unzip -o valtio.zip && rm valtio.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15531.zip -OutFile "$d\valtio.zip"; Expand-Archive "$d\valtio.zip" -DestinationPath $d -Force; ri "$d\valtio.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して valtio.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → valtio フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Valtio

概要

Valtio を使うと、React の状態管理がまるでプレーンな JavaScript のように感じられます。オブジェクトを直接変更すると、React が自動的に再レンダリングされます。リデューサーも、アクションも、セレクターも不要です。オブジェクトを proxy() でラップし、どこからでも変更すると、変更されたプロパティを読み込んでいるコンポーネントが再レンダリングされます。JavaScript の Proxy に基づいており、各コンポーネントがどのプロパティを使用しているかを追跡し、それらの特定のプロパティが変更された場合にのみ再レンダリングします。

どのような時に使うか

  • 可能な限りシンプルな状態管理をしたい場合
  • Redux のボイラープレートや Zustand の set() 関数にうんざりしている場合
  • prop drilling なしでコンポーネント間で状態を共有したい場合
  • React の外部(イベントハンドラー、WebSocket コールバック)からアクセス/変更される状態がある場合
  • チームがイミュータブルなパターンよりもミュータブルなパターンを好む場合

手順

セットアップ

npm install valtio

基本的なストア

// store/app.ts — 状態をプレーンなオブジェクトとして定義
import { proxy, useSnapshot } from "valtio";

export const appState = proxy({
  user: null as { name: string; email: string } | null,
  theme: "light" as "light" | "dark",
  notifications: [] as Array<{ id: string; text: string; read: boolean }>,
  sidebar: { open: true, width: 280 },
});

// 直接変更 — React コンポーネントは自動的に更新
export function login(user: { name: string; email: string }) {
  appState.user = user;
}

export function toggleTheme() {
  appState.theme = appState.theme === "light" ? "dark" : "light";
}

export function addNotification(text: string) {
  appState.notifications.push({ id: crypto.randomUUID(), text, read: false });
}

export function markAllRead() {
  appState.notifications.forEach((n) => { n.read = true; });
}

export function toggleSidebar() {
  appState.sidebar.open = !appState.sidebar.open;
}

コンポーネントでの使用

// components/Header.tsx — useSnapshot で状態を読み込む
import { useSnapshot } from "valtio";
import { appState, toggleTheme, toggleSidebar } from "@/store/app";

export function Header() {
  // useSnapshot は読み取り専用のスナップショットを作成
  // コンポーネントは `user` または `theme` が変更された場合にのみ再レンダリング
  // `notifications` または `sidebar` の変更はここでは再レンダリングをトリガーしない
  const snap = useSnapshot(appState);

  return (
    <header className="flex items-center justify-between p-4">
      <button onClick={toggleSidebar}>☰</button>
      <span>{snap.user?.name ?? "Guest"}</span>
      <button onClick={toggleTheme}>
        {snap.theme === "light" ? "🌙" : "☀️"}
      </button>
    </header>
  );
}
// components/NotificationBell.tsx — 派生/計算された値
import { useSnapshot } from "valtio";
import { appState, markAllRead } from "@/store/app";

export function NotificationBell() {
  const snap = useSnapshot(appState);
  const unread = snap.notifications.filter((n) => !n.read).length;

  return (
    <button onClick={markAllRead} className="relative">
      🔔
      {unread > 0 && (
        <span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
          {unread}
        </span>
      )}
    </button>
  );
}

derive を使用した計算された値

// store/derived.ts — 自動更新される計算された値
import { derive } from "valtio/utils";
import { appState } from "./app";

export const derived = derive({
  unreadCount: (get) => get(appState).notifications.filter((n) => !n.read).length,
  isDarkMode: (get) => get(appState).theme === "dark",
  isLoggedIn: (get) => get(appState).user !== null,
});

React の外部でのサブスクライブ

// コンポーネントの外部で状態の変化をリッスン
import { subscribe } from "valtio";
import { appState } from "./store/app";

// すべての状態の変化をログに記録
subscribe(appState, () => {
  console.log("State changed:", JSON.stringify(appState));
});

// 特定のプロパティをサブスクライブ
subscribe(appState.sidebar, () => {
  localStorage.setItem("sidebar-open", String(appState.sidebar.open));
});

// WebSocket ハンドラーで使用
socket.on("notification", (data) => {
  appState.notifications.push(data);  // コンポーネントは自動的に更新
});

例 1: ショッピングカートの構築

ユーザープロンプト: 「シンプルな状態管理を使用して、追加/削除/数量更新ができるショッピングカートを構築してください。」

エージェントは、カートの状態のための Valtio proxy、配列を直接変更するアクション、およびカートの内容と合計をリアクティブに表示するコンポーネントを作成します。

例 2: テーマとレイアウトのプリファレンス

ユーザープロンプト: 「ページロードをまたいで永続化されるユーザー設定(テーマ、言語、サイドバーの状態)を保存します。」

エージェントは、subscribe を介して localStorage と同期する Valtio ストアと、設定をリアクティブに読み取るコンポーネントを作成します。

ガイドライン

  • 状態には proxy()、読み取りには useSnapshot() — コンポーネントでは常にスナップショットを使用
  • 直接変更state.count++ が機能します。setStateset() は不要です
  • 自動レンダリング最適化 — アクセスされたプロパティが変更された場合にのみ再レンダリング
  • 副作用には subscribe() — localStorage への永続化、ログ、同期
  • 計算された値には derive() — 依存関係が変更されると自動的に再計算
  • React の外部でも動作 — イベントハンドラー、WebSocket、タイマーから変更
  • スナップショットは読み取り専用snap を変更せず、元の proxy を変更
  • 配列は自然に動作pushsplicefilter はすべて再レンダリングをトリガー
  • ネストされたオブジェクトも追跡state.user.name = "new" は再レンダリングをトリガー
  • Devtools — Redux DevTools との統合には import { devtools } from "valtio/utils"
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Valtio

Overview

Valtio makes React state management feel like plain JavaScript — mutate objects directly and React re-renders automatically. No reducers, no actions, no selectors. Wrap an object in proxy(), mutate it anywhere, and components that read the changed properties re-render. Based on JavaScript Proxy, it tracks which properties each component uses and only re-renders when those specific properties change.

When to Use

  • Want the simplest possible state management
  • Tired of Redux boilerplate or Zustand's set() function
  • Sharing state between components without prop drilling
  • State that's accessed/modified outside React (event handlers, WebSocket callbacks)
  • Team prefers mutable patterns over immutable

Instructions

Setup

npm install valtio

Basic Store

// store/app.ts — Define state as a plain object
import { proxy, useSnapshot } from "valtio";

export const appState = proxy({
  user: null as { name: string; email: string } | null,
  theme: "light" as "light" | "dark",
  notifications: [] as Array<{ id: string; text: string; read: boolean }>,
  sidebar: { open: true, width: 280 },
});

// Mutate directly — React components auto-update
export function login(user: { name: string; email: string }) {
  appState.user = user;
}

export function toggleTheme() {
  appState.theme = appState.theme === "light" ? "dark" : "light";
}

export function addNotification(text: string) {
  appState.notifications.push({ id: crypto.randomUUID(), text, read: false });
}

export function markAllRead() {
  appState.notifications.forEach((n) => { n.read = true; });
}

export function toggleSidebar() {
  appState.sidebar.open = !appState.sidebar.open;
}

Use in Components

// components/Header.tsx — Read state with useSnapshot
import { useSnapshot } from "valtio";
import { appState, toggleTheme, toggleSidebar } from "@/store/app";

export function Header() {
  // useSnapshot creates a read-only snapshot
  // Component ONLY re-renders when `user` or `theme` changes
  // Changes to `notifications` or `sidebar` don't trigger re-render here
  const snap = useSnapshot(appState);

  return (
    <header className="flex items-center justify-between p-4">
      <button onClick={toggleSidebar}>☰</button>
      <span>{snap.user?.name ?? "Guest"}</span>
      <button onClick={toggleTheme}>
        {snap.theme === "light" ? "🌙" : "☀️"}
      </button>
    </header>
  );
}
// components/NotificationBell.tsx — Derived/computed values
import { useSnapshot } from "valtio";
import { appState, markAllRead } from "@/store/app";

export function NotificationBell() {
  const snap = useSnapshot(appState);
  const unread = snap.notifications.filter((n) => !n.read).length;

  return (
    <button onClick={markAllRead} className="relative">
      🔔
      {unread > 0 && (
        <span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
          {unread}
        </span>
      )}
    </button>
  );
}

Computed Values with derive

// store/derived.ts — Computed values that auto-update
import { derive } from "valtio/utils";
import { appState } from "./app";

export const derived = derive({
  unreadCount: (get) => get(appState).notifications.filter((n) => !n.read).length,
  isDarkMode: (get) => get(appState).theme === "dark",
  isLoggedIn: (get) => get(appState).user !== null,
});

Subscribe Outside React

// Listen to state changes outside components
import { subscribe } from "valtio";
import { appState } from "./store/app";

// Log every state change
subscribe(appState, () => {
  console.log("State changed:", JSON.stringify(appState));
});

// Subscribe to specific property
subscribe(appState.sidebar, () => {
  localStorage.setItem("sidebar-open", String(appState.sidebar.open));
});

// Use in WebSocket handler
socket.on("notification", (data) => {
  appState.notifications.push(data);  // Components auto-update
});

Examples

Example 1: Build a shopping cart

User prompt: "Build a shopping cart with add/remove/update quantity using simple state management."

The agent will create a Valtio proxy for cart state, actions that directly mutate the array, and components that reactively display cart contents and total.

Example 2: Theme and layout preferences

User prompt: "Store user preferences (theme, language, sidebar state) that persist across page loads."

The agent will create a Valtio store with localStorage sync via subscribe, and components that read preferences reactively.

Guidelines

  • proxy() for state, useSnapshot() for reading — always use snapshot in components
  • Mutate directlystate.count++ works; no setState or set() needed
  • Automatic render optimization — only re-renders when accessed properties change
  • subscribe() for side effects — persist to localStorage, log, sync
  • derive() for computed values — auto-recalculates when dependencies change
  • Works outside React — mutate from event handlers, WebSocket, timers
  • Snapshot is read-only — don't mutate snap, mutate the original proxy
  • Arrays work naturallypush, splice, filter all trigger re-renders
  • Nested objects trackedstate.user.name = "new" triggers re-render
  • Devtoolsimport { devtools } from "valtio/utils" for Redux DevTools integration