К основному содержанию
скилл CX Codex

tanstack-store — скилл для Claude Code: реактивный стор и установка

Скилл по TanStack Store: реактивный стор без привязки к фреймворку, адаптеры для React, Vue, Solid, Angular и Svelte. Пригодится, когда агент пишет состояние на @tanstack/store.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add tanstack-skills/tanstack-skills --skill tanstack-store -a claude-code
Открыть на GitHub

Что делает tanstack-store

Скилл даёт агенту справочник по API TanStack Store. Внутри — Store для состояния, Derived для вычисляемых значений, Effect для побочных эффектов и batch для атомарных обновлений. Обновление состояния идёт через setState с функцией-апдейтером, подписка — через subscribe с возвратом функции отписки.

Отдельный блок про фреймворк-адаптеры. Для React это useStore(store, selector?, equalityFn?) из @tanstack/react-store, для Vue, Solid, Angular и Svelte — свои пакеты и хуки. Есть раздел про shallow для селекторов, возвращающих объекты или массивы: без него компонент перерисовывается на любое изменение состояния, потому что ссылка на объект новая.

Важная деталь, на которой легко споткнуться: у Derived и Effect нужно вызывать mount(), иначе они не работают. Функцию размонтирования возвращает сам mount, и в React её принято отдавать из useEffect. Текст обрезан, поэтому полный список практик может быть шире показанного.

Какие задачи решает

  • завести общий стор без Redux и лишних обёрток
  • посчитать производное значение из двух сторов
  • сгруппировать несколько обновлений в одно уведомление подписчиков
  • подписать React-компонент на часть состояния через селектор
  • повесить побочный эффект с очисткой таймера

Примеры запросов агенту

  • Сделай стор счётчика на @tanstack/store и подключи его в React через useStore
  • Добавь Derived, который фильтрует список по строке поиска, и не забудь mount()
  • Оберни три обновления сторов в batch, чтобы подписчики сработали один раз

Как установить tanstack-store

1Через Skills CLI (Vercel)

npx skills add tanstack-skills/tanstack-skills --skill tanstack-store -a claude-code

2Вручную: положить файлы

~/.claude/skills/tanstack-store/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/tanstack-store/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о tanstack-store

Как установить tanstack-store в Claude?

Выполни npx skills add tanstack-skills/tanstack-skills --skill tanstack-store -a claude-code. Файл скилла окажется в ~/.claude/skills/tanstack-store/SKILL.md.

Что делает tanstack-store?

Учит агента работать с реактивным стором TanStack: Store, Derived, Effect, batch и хуки-адаптеры для React, Vue, Solid, Angular и Svelte.

Почему Derived не обновляется?

Скорее всего, не вызван mount(). Без него Derived и Effect не активны, а возвращённую функцию нужно вызвать при размонтировании.

Исходный текст

SKILL.md · MIT
---
name: tanstack-store
description: Framework-agnostic, immutable reactive data store with framework adapters for React, Vue, Solid, Angular, and Svelte.
---


## Overview

TanStack Store is a lightweight reactive store (signals-like) that powers the internals of TanStack libraries. It provides `Store` for state, `Derived` for computed values, `Effect` for side effects, and `batch` for atomic updates. Framework adapters provide reactive hooks.

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

## Installation

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

## Store

### Creating a Store

```typescript
import { Store } from '@tanstack/store'

const countStore = new Store(0)

const userStore = new Store<{ name: string; email: string }>({
  name: 'Alice',
  email: '[email protected]',
})
```

### Updating State

```typescript
// Function updater (immutable update)
countStore.setState((prev) => prev + 1)

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

### Subscribing to Changes

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

// Cleanup
unsub()
```

### Store Options

```typescript
const store = new Store(initialState, {
  // Custom update function
  updateFn: (prevValue) => (updater) => {
    return updater(prevValue) // custom logic
  },
  // Callback on subscribe
  onSubscribe: (listener, store) => {
    console.log('New subscriber')
    return () => console.log('Unsubscribed')
  },
  // Callback on every update
  onUpdate: () => {
    console.log('State updated:', store.state)
  },
})
```

### Store Properties

```typescript
store.state      // Current state
store.prevState  // Previous state
store.listeners  // Set of listener callbacks
```

## Derived (Computed Values)

```typescript
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],
})

// MUST mount to activate
const unmount = doubled.mount()

console.log(doubled.state) // 10

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

// Cleanup
unmount()
```

### Derived with Previous Value

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

### Chaining Derived

```typescript
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 (Side Effects)

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

const count = new Store(0)

const logger = new Effect({
  deps: [count],
  fn: () => {
    console.log('Count changed:', count.state)
    // Optionally return cleanup function
    return () => console.log('Cleaning up')
  },
  eager: false, // true = run immediately on mount
})

const unmount = logger.mount()

count.setState(() => 1) // logs: "Count changed: 1"

unmount()
```

### Effect with Cleanup

```typescript
const timerEffect = new Effect({
  deps: [intervalStore],
  fn: () => {
    const id = setInterval(() => { /* ... */ }, intervalStore.state)
    return () => clearInterval(id) // cleanup on next run or unmount
  },
})
```

## Batch

Group multiple updates into one notification:

```typescript
import { batch } from '@tanstack/store'

// Subscribers fire only once with final state
batch(() => {
  countStore.setState(() => 1)
  nameStore.setState(() => 'Alice')
  settingsStore.setState((prev) => ({ ...prev, theme: 'dark' }))
})
```

## React Integration

### useStore Hook

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

// Subscribe to full state
function Counter() {
  const count = useStore(countStore)
  return <button onClick={() => countStore.setState((c) => c + 1)}>{count}</button>
}

// Subscribe with selector (performance optimization)
function UserName() {
  const name = useStore(userStore, (state) => state.name)
  return <span>{name}</span>
}

// Subscribe to Derived
function DoubledDisplay() {
  const value = useStore(doubledDerived)
  return <span>{value}</span>
}
```

### shallow Equality Function

Prevents re-renders when selector returns structurally-equal objects:

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

function TodoList() {
  // Without shallow: re-renders on ANY state change (new object ref)
  // With shallow: only re-renders when items actually change
  const items = useStore(todosStore, (state) => state.items, shallow)
  return <ul>{items.map(/* ... */)}</ul>
}
```

### Mounting Derived/Effect in React

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

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

## Module-Level Store Pattern

```typescript
// 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,
})

// Actions as plain functions
export function increment() {
  counterStore.setState((c) => c + 1)
}

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

## Framework Adapters

| Framework | Package | Hook/Composable |
|-----------|---------|-----------------|
| React | `@tanstack/react-store` | `useStore(store, selector?, equalityFn?)` |
| Vue | `@tanstack/vue-store` | `useStore(store, selector?)` (returns computed ref) |
| Solid | `@tanstack/solid-store` | `useStore(store, selector?)` (returns signal) |
| Angular | `@tanstack/angular-store` | `injectStore(store, selector?)` (returns signal) |
| Svelte | `@tanstack/svelte-store` | `useStore(store, selector?)` (returns $state) |

## Best Practices

1. **Define stores at module level** - they're singletons
2. **Use selectors** in `useStore` to prevent unnecessary re-renders
3. **Use `shallow`** when selectors return objects/arrays
4. **Always call `mount()`** on Derived and Effect instances
5. **Always clean up** unmount functions (especially in React useEffect)
6. **Never mutate state directly** - always use `setState`
7. **Use `batch`** for multiple related updates
8. **Use Derived chains** for data transformations (filter -> sort -> paginate)
9. **Return cleanup functions** from Effect `fn` for timers/listeners
10. **Select primitives** when possible (no equality fn needed)

## Common Pitfalls

- Forgetting to `mount()` Derived/Effect (they won't activate)
- Not cleaning up subscriptions/unmount functions (memory leaks)
- Mutating `store.state` directly instead of using `setState`
- Creating new object references in selectors without `shallow`
- Using `useStore` without a selector (subscribes to everything)
- Forgetting `eager: true` when Effect should run immediately

© tanstack-skills · MIT · tanstack-skills/tanstack-skills

Похожие скиллы

Всё по теме «Фронтенд и UI» →
clerk-tanstack-patterns clerk Подсказывает агенту, как подключить Clerk к TanStack React Start: защита маршрутов, createServerFn, лоадеры и middleware. CX Codex +1 15 500установок zustand-store-ts Microsoft Скилл задаёт шаблон стора Zustand на TypeScript: отдельные типы для состояния и действий, middleware subscribeWithSelector, селекторы. 3установок frontend-dev-guidelines davila7 Скилл задаёт агенту единый стиль работы с React и TypeScript: Suspense, ленивая загрузка, структура features, MUI v7 и TanStack. 556установок tanstack-router-best-practices DeckardGer Набор правил по TanStack Router для React: типизация, загрузка данных, search params и навигация. Пригодится, когда роутинг в проекте разрастается. CX Codex +1 7 100установок react-patterns manutej Скилл с готовыми рецептами React: хуки, композиция компонентов, управление состоянием и борьба с лишними ререндерами. CX Codex +1 471установок react-development manutej Скилл для ИИ-агента: подсказывает, как писать компоненты, хуки, состояние и эффекты в React по официальной документации. CX Codex +1 464установок

Из того же набора12

tanstack-form Скилл учит ассистента создавать формы на базе TanStack Form с типизацией TypeScript, валидацией через Zod или Valibot и динамическими массивами полей. CX Codex +1 4 300установок tanstack-pacer Скилл подсказывает агенту, как подключить TanStack Pacer: дебаунс, троттлинг, лимиты запросов, очереди и батчинг в одном пакете. CX Codex +1 3 900установок tanstack-start Скилл помогает создавать и сопровождать приложения на фреймворке TanStack Start с потоковым SSR, серверными функциями и маршрутизацией. CX Codex +1 3 900установок tanstack-virtual Скилл подсказывает агенту, как подключить TanStack Virtual и рисовать только видимые строки в больших списках, таблицах и сетках. CX Codex +1 2 500установок tanstack-devtools Скилл учит агента подключать единую панель отладки TanStack в проектах на React. Помогает настроить плагины для Query, Router и рабочих процессов TanStack AI. CX Codex +1 2 300установок tanstack-cli Скилл проводит агента через создание проекта TanStack Start: подбирает интеграции, генерирует структуру и подсказывает по деплою. CX Codex +1 1 700установок tanstack-ai Скилл обучает ассистента работать с TanStack AI: настраивать стриминг ответов, вызов функций и валидацию схем в React или Solid. CX Codex +1 1 600установок tanstack-config Помогает настроить сборку, версионирование и публикацию пакетов JavaScript и TypeScript по стандартам TanStack. Пригодится при настройке монорепозитория на pnpm и Nx. CX Codex +1 1 500установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой