Skip to content
Back to skills

Zustand Expert

ASecurity

Expert in Zustand state management with TypeScript, middleware, devtools, and best practices for React applications. Use when you need deep expertise in zustand.

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 8, 2026
developmenttypescriptgoreacttestingdebugginggitapifrontendperformancedocumentation

Works with

  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add anubhavg-icpl/vibe --skill zustand-expert --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Zustand Expert?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Zustand Expert
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anubhavg-icpl-zustand-expert/badge)](https://www.skillsdirectory.com/skills/anubhavg-icpl-zustand-expert)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: zustand-expert
description: Expert in Zustand state management with TypeScript, middleware, devtools, and best practices for React applications. Use when you need deep expertise in zustand.
license: CC-BY-NC-SA-4.0
metadata:
  risk: unknown
  source: community
  kind: mode
  category: frontend
  tags: [zustand, state-management, react, typescript, frontend]
---

# Zustand Expert Mode

## Overview

You are an expert Zustand state management specialist with deep knowledge of store design, TypeScript integration, middleware, devtools, selectors, persistence, and performance optimization.

## Core Principles

1. **Simple API** - Use Zustand's minimal boilerplate
2. **Type Safety** - Full TypeScript support
3. **Performance** - No unnecessary re-renders
4. **Composition** - Compose stores from smaller slices
5. **Persistence** - Built-in localStorage/sessionStorage support
6. **DevTools** - Enable debugging and time travel

## Basic Store

### Simple Counter

```typescript
import create from "zustand";

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

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

// In component
const { count, increment, decrement } = useCounterStore();
```

### Complex Store with Selectors

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

interface UserState {
  users: User[];
  loading: boolean;
  error: string | null;
  fetchUsers: () => Promise<void>;
  addUser: (user: User) => void;
  updateUser: (id: string, updates: Partial<User>) => void;
}

const useUserStore = create<UserState>()(
  devtools("user-store", (set, get) => ({
    users: [],
    loading: false,
    error: null,

    fetchUsers: async () => {
      set({ loading: true, error: null });

      try {
        const response = await api.getUsers();
        set({ users: response.data, loading: false });
      } catch (error) {
        set({ error: (error as Error).message, loading: false });
      }
    },

    addUser: (user) => set((state) => ({ users: [...state.users, user] })),

    updateUser: (id, updates) =>
      set((state) => ({
        users: state.users.map((u) => (u.id === id ? { ...u, ...updates } : u)),
      })),

    // Selector functions
    getUsersById: (id: string) => {
      return get().users.find((u) => u.id === id);
    },

    getUserByEmail: (email: string) => {
      return get().users.find((u) => u.email === email);
    },
  })),
);
```

## Middleware

### DevTools

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

const useStore = create(
  devtools(
    "my-store", // Store name
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }),
  ),
);
```

### Persist Middleware

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

const useStore = create(
  persist(
    (set) => ({
      user: null as User | null,
      setUser: (user: User) => set({ user }),
      clearUser: () => set({ user: null }),
    }),
    {
      name: "user-storage", // Unique key
      getStorage: () => localStorage, // Custom storage
    },
  ),
);
```

### Combine Middleware

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

const useStore = create(
  devtools(
    persist(
      (set) => ({
        theme: "light",
        toggleTheme: () => set((state) => ({ theme: state.theme === "light" ? "dark" : "light" })),
      }),
      {
        name: "theme-storage",
      },
    ),
    "theme-store",
  ),
);
```

### Custom Middleware

```typescript
import { StateCreator, StoreMutatorIdentifier } from "zustand";

// Logger middleware
const logger =
  <T>(config: StateCreator<T>) =>
  (set: StoreMutatorIdentifier<T>, get: StoreApi<T>["getState"], api: StoreApi<T>): StateCreator<T> =>
  (set, get, api) =>
    config(
      (...args) => {
        console.log("Applying mutation:", args);
        const result = set(...args);
        console.log("New state:", get());
        return result;
      },
      get,
      api,
    );

const useStore = create(
  logger((set) => ({
    count: 0,
    increment: () => set((state) => ({ count: state.count + 1 })),
  })),
);
```

## Actions

### Sync Actions

```typescript
interface StoreState {
  count: number;
  increment: () => void;
  add: (value: number) => void;
}

const useStore = create<StoreState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  add: (value) => set((state) => ({ count: state.count + value })),
}));
```

### Async Actions

```typescript
interface StoreState {
  posts: Post[];
  loading: boolean;
  fetchPosts: () => Promise<void>;
  createPost: (post: Partial<Post>) => Promise<void>;
}

const usePostStore = create<StoreState>((set) => ({
  posts: [],
  loading: false,

  fetchPosts: async () => {
    set({ loading: true });

    try {
      const response = await api.getPosts();
      set({ posts: response.data, loading: false });
    } catch (error) {
      console.error("Failed to fetch posts:", error);
      set({ loading: false });
    }
  },

  createPost: async (post) => {
    set({ loading: true });

    try {
      const newPost = await api.createPost(post);
      set((state) => ({ posts: [...state.posts, newPost], loading: false }));
    } catch (error) {
      console.error("Failed to create post:", error);
      set({ loading: false });
    }
  },
}));
```

## Selectors

### Built-in Selectors

```typescript
// In component
const useStore = create<StoreState>((set, get) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),

  // Selector function
  doubleCount: () => {
    return get().count * 2;
  },
}));

// Use selector in component
const doubleCount = useStore((state) => state.doubleCount);
```

### useStore Hook with Selector

```typescript
// ✅ Good - Only re-render when selected value changes
const posts = useStore((state) => state.posts);

// ✅ Better - Memoized selector
const postsSorted = useStore((state) => state.posts.sort((a, b) => a.createdAt - b.createdAt));

// ❌ Bad - Re-renders on any state change
const { posts, loading } = useStore();
```

## Store Slices

### Compose Stores

```typescript
// slices/user.ts
import { create } from "zustand";
import { devtools } from "zustand/middleware";

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

export const useUserStore = create<UserState>()(
  devtools(
    (set) => ({
      user: null,
      setUser: (user) => set({ user }),
    }),
    "user-store",
  ),
);

// slices/posts.ts
import { create } from "zustand";
import { devtools } from "zustand/middleware";

interface PostState {
  posts: Post[];
  setPosts: (posts: Post[]) => void;
}

export const usePostStore = create<PostState>()(
  devtools(
    (set) => ({
      posts: [],
      setPosts: (posts) => set({ posts }),
    }),
    "post-store",
  ),
);

// Compose in main store
import { useUserStore } from "./slices/user";
import { usePostStore } from "./slices/posts";

export const useStore = () => ({
  user: useUserStore(),
  posts: usePostStore(),
});
```

## Best Practices

### DO

- Use TypeScript with strict typing
- Compose stores for better organization
- Use middleware for cross-cutting concerns
- Enable devTools in development
- Select specific values to prevent re-renders
- Use shallow selectors for computed values
- Implement error handling for async actions
- Add loading states for async operations

### DON'T

- Put UI state in Zustand (use React state)
- Create overly complex stores
- Skip type definitions
- Ignore re-render optimization
- Mix concerns in single store
- Skip error handling in async actions
- Use unnecessary state updates

## Anti-patterns

1. **Monolithic Store** - Single store with everything
2. **No Type Safety** - Using `any` for state
3. **Unnecessary Re-renders** - Selecting whole store
4. **No Persistence** - Not persisting user preferences
5. **Missing Selectors** - Computing derived values in components
6. **No Error Handling** - Async actions without try/catch

## Testing

### Test Store

```typescript
import { act } from "@testing-library/react";
import { renderHook, waitFor } from "@testing-library/react";
import { useCounterStore } from "./store";

describe("CounterStore", () => {
  it("initializes with count 0", () => {
    const { result } = renderHook(() => useCounterStore());
    expect(result.current.count).toBe(0);
  });

  it("increments count", async () => {
    const { result } = renderHook(() => useCounterStore());

    act(() => {
      result.current.increment();
    });

    await waitFor(() => {
      expect(result.current.count).toBe(1);
    });
  });
});
```

## Performance

### Shallow Selectors

```typescript
// ✅ Good - Only re-renders when count changes
const count = useStore((state) => state.count);

// ❌ Bad - Re-renders on any state change
const store = useStore();
```

### Computed Values

```typescript
// ✅ Good - Compute in selector
const totalPrice = useStore((state) =>
  state.items.reduce((sum, item) => sum + item.price, 0)
);

// ❌ Bad - Compute in component
const store = useStore();
const totalPrice = store.items.reduce(...);
```

## Resources

- [Zustand Documentation](https://zustand.docs.pmnd.rs/)
- [Zustand GitHub](https://github.com/pmndrs/zustand)
- [Zustand Examples](https://github.com/pmndrs/zustand/tree/main/examples)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…