Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 50/100

tanstack-store

フレームワークに依存しない不変のリアクティブデータストアで、React・Vue・Solid・Angular・Svelte向けのアダプターを提供します。

description の原文を見る

Framework-agnostic, immutable reactive data store with framework adapters for React, Vue, Solid, Angular, and Svelte.

SKILL.md 本文

概要

TanStack Store は、TanStack ライブラリの内部を支える軽量なリアクティブストア(signals のような)です。状態管理用の Store、計算値用の Derived、副作用用の Effect、アトミック更新用の batch を提供します。フレームワークアダプターはリアクティブなフックを提供します。

Core: @tanstack/store React: @tanstack/react-store

インストール

npm install @tanstack/store @tanstack/react-store

Store

Store の作成

import { Store } from '@tanstack/store'

const countStore = new Store(0)

const userStore = new Store<{ name: string; email: string }>({
  name: 'Alice',
  email: 'alice@example.com',
})

状態の更新

// 関数 updater(イミュータブルな更新)
countStore.setState((prev) => prev + 1)

userStore.setState((prev) => ({ ...prev, name: 'Bob' }))

変更の監視

const unsub = countStore.subscribe(() => {
  console.log('Count:', countStore.state)
})

// クリーンアップ
unsub()

Store オプション

const store = new Store(initialState, {
  // カスタム更新関数
  updateFn: (prevValue) => (updater) => {
    return updater(prevValue) // カスタムロジック
  },
  // 購読時のコールバック
  onSubscribe: (listener, store) => {
    console.log('New subscriber')
    return () => console.log('Unsubscribed')
  },
  // 更新時のコールバック
  onUpdate: () => {
    console.log('State updated:', store.state)
  },
})

Store プロパティ

store.state      // 現在の状態
store.prevState  // 前の状態
store.listeners  // リスナーコールバックのセット

Derived(計算値)

import { Store, Derived } from '@tanstack/store'

const count = new Store(5)
const multiplier = new Store(2)

const doubled = new Derived({
  deps: [count, multiplier],
  fn: ({ currDepVals }) => currDepVals[0] * currDepVals[1],
})

// アクティブ化するために必ずマウント
const unmount = doubled.mount()

console.log(doubled.state) // 10

count.setState(() => 10)
console.log(doubled.state) // 20

// クリーンアップ
unmount()

前の値を使用した Derived

const accumulated = new Derived({
  deps: [count],
  fn: ({ prevVal, currDepVals }) => {
    return currDepVals[0] + (prevVal ?? 0)
  },
})

Derived の連鎖

const filtered = new Derived({
  deps: [dataStore, filterStore],
  fn: ({ currDepVals }) => currDepVals[0].filter(matchesFilter(currDepVals[1])),
})

const sorted = new Derived({
  deps: [filtered, sortStore],
  fn: ({ currDepVals }) => [...currDepVals[0]].sort(comparator(currDepVals[1])),
})

const paginated = new Derived({
  deps: [sorted, pageStore],
  fn: ({ currDepVals }) => currDepVals[0].slice(
    currDepVals[1].offset,
    currDepVals[1].offset + currDepVals[1].limit,
  ),
})

Effect(副作用)

import { Store, Effect } from '@tanstack/store'

const count = new Store(0)

const logger = new Effect({
  deps: [count],
  fn: () => {
    console.log('Count changed:', count.state)
    // オプションでクリーンアップ関数を返す
    return () => console.log('Cleaning up')
  },
  eager: false, // true = マウント時に即座に実行
})

const unmount = logger.mount()

count.setState(() => 1) // ログ出力: "Count changed: 1"

unmount()

クリーンアップ付き Effect

const timerEffect = new Effect({
  deps: [intervalStore],
  fn: () => {
    const id = setInterval(() => { /* ... */ }, intervalStore.state)
    return () => clearInterval(id) // 次の実行またはアンマウント時にクリーンアップ
  },
})

Batch

複数の更新を 1 つの通知にグループ化:

import { batch } from '@tanstack/store'

// 購読者は最終的な状態で 1 回だけ起動
batch(() => {
  countStore.setState(() => 1)
  nameStore.setState(() => 'Alice')
  settingsStore.setState((prev) => ({ ...prev, theme: 'dark' }))
})

React インテグレーション

useStore フック

import { useStore } from '@tanstack/react-store'

// 全状態を購読
function Counter() {
  const count = useStore(countStore)
  return <button onClick={() => countStore.setState((c) => c + 1)}>{count}</button>
}

// セレクターで購読(パフォーマンス最適化)
function UserName() {
  const name = useStore(userStore, (state) => state.name)
  return <span>{name}</span>
}

// Derived を購読
function DoubledDisplay() {
  const value = useStore(doubledDerived)
  return <span>{value}</span>
}

shallow 等値関数

セレクターが構造的に等しいオブジェクトを返す場合、再レンダリングを防止:

import { useStore } from '@tanstack/react-store'
import { shallow } from '@tanstack/react-store'

function TodoList() {
  // shallow なし: 状態変更時に再レンダリング(新しいオブジェクト参照)
  // shallow あり: items が実際に変わった時のみ再レンダリング
  const items = useStore(todosStore, (state) => state.items, shallow)
  return <ul>{items.map(/* ... */)}</ul>
}

React で Derived/Effect をマウント

function MyComponent() {
  useEffect(() => {
    const unmountDerived = myDerived.mount()
    const unmountEffect = myEffect.mount()
    return () => {
      unmountDerived()
      unmountEffect()
    }
  }, [])

  const value = useStore(myDerived)
  return <span>{value}</span>
}

モジュールレベル Store パターン

// stores/counter.ts
import { Store, Derived } from '@tanstack/store'

export const counterStore = new Store(0)

export const doubledCount = new Derived({
  deps: [counterStore],
  fn: ({ currDepVals }) => currDepVals[0] * 2,
})

// プレーンな関数としてのアクション
export function increment() {
  counterStore.setState((c) => c + 1)
}

export function reset() {
  counterStore.setState(() => 0)
}

フレームワークアダプター

フレームワークパッケージフック/コンポーザブル
React@tanstack/react-storeuseStore(store, selector?, equalityFn?)
Vue@tanstack/vue-storeuseStore(store, selector?) (computed ref を返す)
Solid@tanstack/solid-storeuseStore(store, selector?) (signal を返す)
Angular@tanstack/angular-storeinjectStore(store, selector?) (signal を返す)
Svelte@tanstack/svelte-storeuseStore(store, selector?) ($state を返す)

ベストプラクティス

  1. モジュールレベルで store を定義 - シングルトンです
  2. useStore でセレクターを使用 - 不要な再レンダリングを防止
  3. セレクターがオブジェクト/配列を返す場合は shallow を使用
  4. Derived と Effect インスタンスで必ず mount() を呼び出す
  5. 必ずクリーンアップ関数をアンマウント(特に React useEffect)
  6. 状態を直接ミューテートしない - 常に setState を使用
  7. 複数の関連する更新には batch を使用
  8. データ変換には Derived チェーンを使用(filter → sort → paginate)
  9. Effect の fn からクリーンアップ関数を返す (タイマー/リスナー用)
  10. プリミティブを選択 (等値関数は不要)

よくある落とし穴

  • Derived/Effect の mount() 呼び出し忘れ(アクティブ化されません)
  • 購読/アンマウント関数のクリーンアップ忘れ(メモリリーク)
  • setState の代わりに store.state を直接ミューテート
  • shallow なしでセレクターで新しいオブジェクト参照を作成
  • セレクターなしで useStore を使用(すべてを購読)
  • Effect が即座に実行されるべき場合に eager: true を忘れる

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
tanstack-skills
リポジトリ
tanstack-skills/tanstack-skills
ライセンス
MIT
最終更新
不明

Source: https://github.com/tanstack-skills/tanstack-skills / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: tanstack-skills · tanstack-skills/tanstack-skills · ライセンス: MIT