К основному содержанию
скилл Claude Code CX Codex Cursor GitHub Copilot

zustand-5 — скилл для Claude Code: состояние на клиенте

Скилл с паттернами управления состоянием в Zustand 5: базовые хранилища, селекторы, persist-middleware и разделение логики на слайсы. Помогает писать чистый реактивный код без лишних ре-рендеров.

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

Что делает zustand-5

Zustand — лёгкая библиотека для состояния без бойлерплейта Redux. Скилл показывает, как создать хранилище с методами, подписаться на нужные поля через селекторы, сохранить данные в localStorage через persist-middleware. Включены примеры асинхронных действий (загрузка данных), работы с Immer для удобных мутаций и паттерна слайсов, когда логику разбивают на отдельные куски и потом объединяют в одно хранилище.

Важно: селекторы предотвращают лишние ре-рендеры, потому что компонент следит только за нужным куском состояния, а не за всем хранилищем сразу. Для нескольких полей используй useShallow из zustand/react/shallow. За пределами React доступны getState() для прямого доступа и subscribe() для подписки на изменения.

Скилл работает на всех основных AI-редакторах и требует установки как модуля проекта. Примеры охватывают типичные сценарии: счётчик, настройки с сохранением, загрузку юзера с обработкой ошибок, список товаров в корзине.

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

  • Управлять клиентским состоянием без бойлерплейта
  • Оптимизировать ре-рендеры компонентов при изменении состояния
  • Сохранять данные в localStorage и восстанавливать при загрузке
  • Организовать асинхронные действия в хранилище
  • Разбить большое состояние на логические слайсы

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

  • Создай хранилище Zustand для счётчика с методами increment и decrement
  • Добавь persist-middleware, чтобы тема сохранялась в localStorage
  • Напиши селектор, который загружает юзера по ID и обновляет состояние

Как установить zustand-5

1Через Skills CLI (Vercel)

npx skills add prowler-cloud/prowler --skill zustand-5 -a claude-code

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

~/.claude/skills/zustand-5/SKILL.md

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

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

Весь набор →

Похожие

visual-edit-precision Adit Jain Скилл для целевых изменений UI, когда вы показываете элементы на скриншоте или указываете их прямо в коде. Меняет только то, что вы выделили, без рефакторинга всего компонента. Claude Code CX Codex Cursor 2 800установок image vercel-labs Превращает JSON-спецификации в SVG и PNG через Satori. Пригодится для OG-картинок, социальных карточек и рендера изображений по схемам от ИИ. Claude Code CX Codex Cursor +1 1 500установок huggingface-gradio huggingface Скилл помогает создавать и редактировать веб-интерфейсы на Gradio в Python. Он пригодится при сборке демоверсий моделей, настройке макетов и чат-ботов. Claude Code CX Codex Cursor +1 2 300установок text-and-bitmaptext phaserjs Скилл помогает ИИ-агенту выводить и настраивать текст в Phaser 4. Нужен при вёрстке интерфейса, настройке стилей и рендеринге шрифтов. Claude Code CX Codex Cursor +1 816установок write-e2e-tests tldraw Помогает писать Playwright E2E-тесты для tldraw: действия в интерфейсе, меню и фигуры на холсте. Нужен при добавлении тестов в примеры SDK или клиент tldraw.com. Claude Code CX Codex Cursor +1 430установок game-object-components phaserjs Справочник по компонентам и миксинам игровых объектов в Phaser 4. Помогает агенту настраивать Transform, Depth и WebGL-эффекты. Claude Code CX Codex Cursor +1 796установок frontend-design официальный anthropics Скилл задаёт осмысленное визуальное направление для новых интерфейсов и редизайна. Подойдёт, когда стандартный шаблонный UI не устраивает. Claude Code Claude.ai 1 025 790установок design-taste-frontend Leonxlnx Скилл задаёт арт-дирекцию для публичных страниц и рабочих экранов, а затем проверяет результат в браузере по скриншотам. Нужен, когда интерфейс выглядит шаблонным или недоработанным. Claude Code CX Codex Cursor +1 673 100установок

Вопросы о zustand-5

Как установить zustand-5 для Claude Code?

Выполни npx skills add prowler-cloud/prowler --skill zustand-5 -a claude-code, затем открой ~/.claude/skills/zustand-5/SKILL.md.

Что делает zustand-5?

Предоставляет готовые паттерны и примеры кода для Zustand 5: простые хранилища, селекторы для оптимизации, сохранение в localStorage, асинхронные действия, разделение на слайсы и работу с Immer.

Почему селекторы важны в Zustand?

Селектор следит только за нужным куском состояния, поэтому компонент не ре-рендерится, когда меняется другая часть хранилища. Используй useShallow для нескольких полей, чтобы избежать лишних обновлений.

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

SKILL.md · Apache-2.0
---
name: zustand-5
description: >
  Zustand 5 state management patterns.
  Trigger: When implementing client-side state with Zustand (stores, selectors, persist middleware, slices).
license: Apache-2.0
metadata:
  author: prowler-cloud
  version: "1.0"
  scope: [root, ui]
  auto_invoke: "Using Zustand stores"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
---

## Basic Store

```typescript
import { create } from "zustand";

interface CounterStore {
  count: number;
  increment: () => void;
  decrement: () => void;
  reset: () => void;
}

const useCounterStore = create<CounterStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 }),
}));

// Usage
function Counter() {
  const { count, increment, decrement } = useCounterStore();
  return (
    <div>
      <span>{count}</span>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}
```

## Persist Middleware

```typescript
import { create } from "zustand";
import { persist } from "zustand/middleware";

interface SettingsStore {
  theme: "light" | "dark";
  language: string;
  setTheme: (theme: "light" | "dark") => void;
  setLanguage: (language: string) => void;
}

const useSettingsStore = create<SettingsStore>()(
  persist(
    (set) => ({
      theme: "light",
      language: "en",
      setTheme: (theme) => set({ theme }),
      setLanguage: (language) => set({ language }),
    }),
    {
      name: "settings-storage",  // localStorage key
    }
  )
);
```

## Selectors (Zustand 5)

```typescript
// ✅ Select specific fields to prevent unnecessary re-renders
function UserName() {
  const name = useUserStore((state) => state.name);
  return <span>{name}</span>;
}

// ✅ For multiple fields, use useShallow
import { useShallow } from "zustand/react/shallow";

function UserInfo() {
  const { name, email } = useUserStore(
    useShallow((state) => ({ name: state.name, email: state.email }))
  );
  return <div>{name} - {email}</div>;
}

// ❌ AVOID: Selecting entire store (causes re-render on any change)
const store = useUserStore();  // Re-renders on ANY state change
```

## Async Actions

```typescript
interface UserStore {
  user: User | null;
  loading: boolean;
  error: string | null;
  fetchUser: (id: string) => Promise<void>;
}

const useUserStore = create<UserStore>((set) => ({
  user: null,
  loading: false,
  error: null,

  fetchUser: async (id) => {
    set({ loading: true, error: null });
    try {
      const response = await fetch(`/api/users/${id}`);
      const user = await response.json();
      set({ user, loading: false });
    } catch (error) {
      set({ error: "Failed to fetch user", loading: false });
    }
  },
}));
```

## Slices Pattern

```typescript
// userSlice.ts
interface UserSlice {
  user: User | null;
  setUser: (user: User) => void;
  clearUser: () => void;
}

const createUserSlice = (set): UserSlice => ({
  user: null,
  setUser: (user) => set({ user }),
  clearUser: () => set({ user: null }),
});

// cartSlice.ts
interface CartSlice {
  items: CartItem[];
  addItem: (item: CartItem) => void;
  removeItem: (id: string) => void;
}

const createCartSlice = (set): CartSlice => ({
  items: [],
  addItem: (item) => set((state) => ({ items: [...state.items, item] })),
  removeItem: (id) => set((state) => ({
    items: state.items.filter(i => i.id !== id)
  })),
});

// store.ts
type Store = UserSlice & CartSlice;

const useStore = create<Store>()((...args) => ({
  ...createUserSlice(...args),
  ...createCartSlice(...args),
}));
```

## Immer Middleware

```typescript
import { create } from "zustand";
import { immer } from "zustand/middleware/immer";

interface TodoStore {
  todos: Todo[];
  addTodo: (text: string) => void;
  toggleTodo: (id: string) => void;
}

const useTodoStore = create<TodoStore>()(
  immer((set) => ({
    todos: [],

    addTodo: (text) => set((state) => {
      // Mutate directly with Immer!
      state.todos.push({ id: crypto.randomUUID(), text, done: false });
    }),

    toggleTodo: (id) => set((state) => {
      const todo = state.todos.find(t => t.id === id);
      if (todo) todo.done = !todo.done;
    }),
  }))
);
```

## DevTools

```typescript
import { create } from "zustand";
import { devtools } from "zustand/middleware";

const useStore = create<Store>()(
  devtools(
    (set) => ({
      // store definition
    }),
    { name: "MyStore" }  // Name in Redux DevTools
  )
);
```

## Outside React

```typescript
// Access store outside components
const { count, increment } = useCounterStore.getState();
increment();

// Subscribe to changes
const unsubscribe = useCounterStore.subscribe(
  (state) => console.log("Count changed:", state.count)
);
```

© prowler-cloud · Apache-2.0 · prowler-cloud/prowler

Смотрите также

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

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