zustand-5

import { create } from "zustand";

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "zustand-5" with this command: npx skills add poletron/custom-rules/poletron-custom-rules-zustand-5

Basic Store

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

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)

// ✅ 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

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

// 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

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

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

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

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

lancedb

No summary provided by upstream source.

Repository SourceNeeds Review
General

javascript-mastery

No summary provided by upstream source.

Repository SourceNeeds Review
General

trpc

No summary provided by upstream source.

Repository SourceNeeds Review
General

git-flow

No summary provided by upstream source.

Repository SourceNeeds Review