From harness-claude
Creates lightweight Zustand global stores with minimal boilerplate for state management without Redux complexity. Covers store creation, selector-based subscriptions, and external store access.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:state-zustand-storeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Create lightweight global stores with Zustand's create function for minimal-boilerplate state management
Create lightweight global stores with Zustand's create function for minimal-boilerplate state management
create from Zustand. Define state and actions together in one function.set to update state.set shallow-merges by default. For nested updates, use the spread operator or the Immer middleware.useStore.getState() and useStore.setState().// stores/auth-store.ts
import { create } from 'zustand';
interface User {
id: string;
name: string;
email: string;
}
interface AuthStore {
user: User | null;
isAuthenticated: boolean;
login: (user: User) => void;
logout: () => void;
updateProfile: (updates: Partial<User>) => void;
}
export const useAuthStore = create<AuthStore>((set) => ({
user: null,
isAuthenticated: false,
login: (user) => set({ user, isAuthenticated: true }),
logout: () => set({ user: null, isAuthenticated: false }),
updateProfile: (updates) =>
set((state) => ({
user: state.user ? { ...state.user, ...updates } : null,
})),
}));
// Component usage — select only what you need
function UserGreeting() {
const userName = useAuthStore((state) => state.user?.name);
return <h1>Hello, {userName ?? 'Guest'}</h1>;
}
function LoginButton() {
const { login, isAuthenticated } = useAuthStore();
// Warning: destructuring without selector subscribes to ALL changes
// Prefer: const login = useAuthStore((state) => state.login);
}
// Outside React
async function fetchAndSetUser() {
const user = await fetch('/api/me').then((r) => r.json());
useAuthStore.getState().login(user);
}
Why selectors matter: Calling useAuthStore() with no argument subscribes to the entire store — the component re-renders on ANY state change. Always pass a selector to subscribe to only what the component needs.
set function behavior: set shallow-merges the object you pass with the current state. It does NOT deep merge. For nested state:
// Wrong — this replaces settings entirely
set({ settings: { theme: 'dark' } });
// Right — spread to preserve other fields
set((state) => ({ settings: { ...state.settings, theme: 'dark' } }));
get for reading current state in actions:
const useStore = create<Store>((set, get) => ({
items: [],
addItem: (item) => {
const current = get().items;
if (current.length >= 100) return; // Read before write
set({ items: [...current, item] });
},
}));
Store outside React: Zustand stores are vanilla JavaScript. useStore.getState() reads without subscribing. useStore.subscribe(listener) sets up manual subscriptions. This makes Zustand usable in Node.js, tests, and non-React code.
TypeScript pattern: Always define the store interface explicitly. Relying on inference from the create callback produces less readable types and breaks IDE autocompletion for complex stores.
https://zustand.docs.pmnd.rs/getting-started/introduction
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeCreates and manages Zustand stores with selectors, persistence, devtools, and middleware. Useful for global state in React or vanilla JavaScript.
Creates and manages Zustand stores for React state management, covering creation, selectors, actions, updates, and performance best practices like shallow equality.
Creates TypeScript Zustand stores using subscribeWithSelector middleware, state/action separation, selectors, and non-React subscriptions for React state management.