bobmatnyc/claude-mpm-skills2 files

Zustand

Minimal, unopinionated state management library for React with simple hook-based API, no providers, and minimal boilerplate for global state without Redux complexity.

Specification
Skill ID
bobmatnyc/claude-mpm-skills/zustand
Publisher
bobmatnyc
Repository
claude-mpm-skills
Installs
0
Files
2
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

bobmatnyc/claude-mpm-skills/zustandInstalls these files
  • SKILL.md
  • metadata.json

What this skill tells the agent

Zustand State Management

Summary

Zustand is a minimal, unopinionated state management library for React. No providers, no boilerplate—just a simple hook-based API that feels natural in React applications.

When to Use

  • React apps needing global state without Redux complexity
  • Projects wanting minimal boilerplate and bundle size
  • Teams preferring direct state mutations over reducers
  • SSR applications (Next.js) requiring flexible state hydration
  • Migrating from Redux/Context API to simpler solution

Quick Start

npm install zustand
// stores/useCounterStore.ts
import { create } from 'zustand'

interface CounterState {
  count: number
  increment: () => void
  decrement: () => void
}

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

// components/Counter.tsx
import { useCounterStore } from '@/stores/useCounterStore'

export function Counter() {
  const { count, increment, decrement } = useCounterStore()

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  )
}

Complete Zustand Guide

Core Concepts

Store Creation

import { create } from 'zustand'

// Basic store
interface BearState {
  bears: number
  addBear: () => void
}

const useBearStore = create<BearState>((set) => ({
  bears: 0,
  addBear: () => set((state) => ({ bears: state.bears + 1 })),
}))

// Store with get access
const useStore = create<State>((set, get) => ({
  count: 0,
  increment: () => {
    const currentCount = get().count
    set({ count: currentCount + 1 })
  },
}))

State Access Patterns

// Select entire store (re-renders on any change)
const state = useStore()

// Select specific fields (re-renders only when these change)
const bears = useStore((state) => state.bears)
const addBear = useStore((state) => state.addBear)

// Destructure with selector
const { bears, addBear } = useStore((state) => ({
  bears: state.bears,
  addBear: state.addBear,
}))

// Multiple selectors
const bears = useStore((state) => state.bears)
const fish = useStore((state) => state.fish)

Mutations

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

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

  // Add item
  addTodo: (text) => set((state) => ({
    todos: [...state.todos, { id: nanoid(), text, completed: false }]
  })),

  // Update item
  toggleTodo: (id) => set((state) => ({
    todos: state.todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    )
  })),

  // Remove item
  removeTodo: (id) => set((state) => ({
    todos: state.todos.filter(todo => todo.id !== id)
  })),
}))

React Integration

useStore Hook

function BearCounter() {
  // Re-renders when bears changes
  const bears = useBearStore((state) => state.bears)
  return <h1>{bears} bears around here...</h1>
}

function Controls() {
  // Doesn't re-render when bears changes
  const addBear = useBearStore((state) => state.addBear)
  return <button onClick={addBear}>Add bear</button>
}

Shallow Comparison

import { shallow } from 'zustand/shallow'

// Prevent re-renders when object identity changes but values don't
const { nuts, honey } = useBearStore(
  (state) => ({ nuts: state.nuts, honey: state.honey }),
  shallow
)

// Custom equality function
const treats = useBearStore(
  (state) => state.treats,
  (prev, next) => prev.length === next.length
)

Outside React Components

// Read state
const count = useStore.getState().count

// Subscribe to changes
const unsubscribe = useStore.subscribe(
  (state) => console.log('Count changed:', state.count)
)

// Update state
useStore.setState({ count: 42 })

// Update with function
useStore.setState((state) => ({ count: state.count + 1 }))

TypeScript Patterns

Typed Store Creation

interface UserState {
  user: User | null
  setUser: (user: User) => void
  clearUser: () => void
}

const useUserStore = create<UserState>((set) => ({
  user: null,
  setUser: (user) => set({ user }),
  clearUser: () => set({ user: null }),
}))

// Type inference works automatically
const user = useUserStore((state) => state.user) // User | null

Store Type Inference

// Extract store type
type UserStoreState = ReturnType<typeof useUserStore.getState>

// Selector type helper
type Selector<T> = (state: UserState) => T

const selectUsername: Selector<string | undefined> = (state) =>
  state.user?.name

Combining Multiple Stores

// Type-safe store combination
function useHybridStore<T, U>(
  selector1: (state: State1) => T,
  selector2: (state: State2) => U
): [T, U] {
  return [
    useStore1(selector1),
    useStore2(selector2),
  ]
}

const [user, theme] = useHybridStore(
  (s) => s.user,
  (s) => s.theme
)

Slices Pattern

Creating Slices

// authSlice.ts
export interface AuthSlice {
  user: User | null
  login: (credentials: Credentials) => Promise<void>
  logout: () => void
}

export const createAuthSlice: StateCreator<
  AuthSlice & TodoSlice,
  [],
  [],
  AuthSlice
> = (set) => ({
  user: null,
  login: async (credentials) => {
    const user = await api.login(credentials)
    set({ user })
  },
  logout: () => set({ user: null }),
})

// todoSlice.ts
export interface TodoSlice {
  todos: Todo[]
  addTodo: (text: string) => void
}

export const createTodoSlice: StateCreator<
  AuthSlice & TodoSlice,
  [],
  [],
  TodoSlice
> = (set) => ({
  todos: [],
  addTodo: (text) => set((state) => ({
    todos: [...state.todos, { id: nanoid(), text, completed: false }]
  })),
})

// store.ts
import { create } from 'zustand'
import { createAuthSlice, AuthSlice } from './authSlice'
import { createTodoSlice, TodoSlice } from './todoSlice'

export const useStore = create<AuthSlice & TodoSlice>()((...a) => ({
  ...createAuthSlice(...a),
  ...createTodoSlice(...a),
}))

Cross-Slice Communication

export const createTodoSlice: StateCreator<
  AuthSlice & TodoSlice,
  [],
  [],
  TodoSlice
> = (set, get) => ({
  todos: [],
  addTodo: (text) => {
    // Access other slice's state
    const user = get().user
    if (!user) throw new Error('Not authenticated')

    set((state) => ({
      todos: [...state.todos, {
        id: nanoid(),
        text,
        userId: user.id,
        completed: false
      }]
    }))
  },
})

Middleware

Persist Middleware

import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface PreferencesState {
  theme: 'light' | 'dark'
  language: string
  setTheme: (theme: 'light' | 'dark') => void
}

export const usePreferencesStore = create<PreferencesState>()(
  persist(
    (set) => ({
      theme: 'light',
      language: 'en',
      setTheme: (theme) => set({ theme }),
    }),
    {
      name: 'preferences-storage', // localStorage key
      storage: createJSONStorage(() => localStorage),

      // Partial persistence
      partialize: (state) => ({ theme: state.theme }),

      // Migration between versions
      version: 1,
      migrate: (persistedState: any, version: number) => {
        if (version === 0) {
          // Migrate from v0 to v1
          persistedState.language = 'en'
        }
        return persistedState as PreferencesState
      },
    }
  )
)

// Custom storage (e.g., AsyncStorage for React Native)
const customStorage = {
  getItem: async (name: string) => {
    const value = await AsyncStorage.getItem(name)
    return value ?? null
  },
  setItem: async (name: string, value: string) => {

Use this skill in a project

Open any RiverX project, search the Skills panel for bobmatnyc/claude-mpm-skills/zustand, and install it in one click.

Use this skill