zustand-store
Create Zustand stores with TypeScript, subscribeWithSelector middleware, and proper state/action separation. Use when building React state management, creating global stores, or implementing reactive state patterns with Zustand.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install microsoft-agent-skills-zustand-store
Repository
Skill path: .github/skills/zustand-store
Create Zustand stores with TypeScript, subscribeWithSelector middleware, and proper state/action separation. Use when building React state management, creating global stores, or implementing reactive state patterns with Zustand.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack, Frontend.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: microsoft.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install zustand-store into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/microsoft/agent-skills before adding zustand-store to shared team environments
- Use zustand-store for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: zustand-store
description: Create Zustand stores with TypeScript, subscribeWithSelector middleware, and proper state/action separation. Use when building React state management, creating global stores, or implementing reactive state patterns with Zustand.
---
# Zustand Store
Create Zustand stores following established patterns with proper TypeScript types and middleware.
## Quick Start
Copy the template from [assets/template.ts](assets/template.ts) and replace placeholders:
- `{{StoreName}}` → PascalCase store name (e.g., `Project`)
- `{{description}}` → Brief description for JSDoc
## Always Use subscribeWithSelector
```typescript
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
export const useMyStore = create<MyStore>()(
subscribeWithSelector((set, get) => ({
// state and actions
}))
);
```
## Separate State and Actions
```typescript
export interface MyState {
items: Item[];
isLoading: boolean;
}
export interface MyActions {
addItem: (item: Item) => void;
loadItems: () => Promise<void>;
}
export type MyStore = MyState & MyActions;
```
## Use Individual Selectors
```typescript
// Good - only re-renders when `items` changes
const items = useMyStore((state) => state.items);
// Avoid - re-renders on any state change
const { items, isLoading } = useMyStore();
```
## Subscribe Outside React
```typescript
useMyStore.subscribe(
(state) => state.selectedId,
(selectedId) => console.log('Selected:', selectedId)
);
```
## Integration Steps
1. Create store in `src/frontend/src/store/`
2. Export from `src/frontend/src/store/index.ts`
3. Add tests in `src/frontend/src/store/*.test.ts`
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### assets/template.ts
```typescript
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
// ============================================================================
// Types
// ============================================================================
/**
* {{StoreName}}State - The state shape for this store
*/
export interface {{StoreName}}State {
// Add state properties
items: unknown[];
selectedId: string | null;
isLoading: boolean;
error: string | null;
}
/**
* {{StoreName}}Actions - Actions that can be performed on this store
*/
export interface {{StoreName}}Actions {
// Setters
setItems: (items: unknown[]) => void;
setSelectedId: (id: string | null) => void;
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
// Complex actions
loadItems: () => Promise<void>;
addItem: (item: unknown) => void;
removeItem: (id: string) => void;
// Reset
reset: () => void;
}
/**
* {{StoreName}}Store - Combined store type
*/
export type {{StoreName}}Store = {{StoreName}}State & {{StoreName}}Actions;
// ============================================================================
// Initial State
// ============================================================================
const initialState: {{StoreName}}State = {
items: [],
selectedId: null,
isLoading: false,
error: null,
};
// ============================================================================
// Store
// ============================================================================
/**
* use{{StoreName}}Store - Zustand store for managing {{description}}
*
* @example
* ```typescript
* // In a component - use individual selectors for performance
* const items = use{{StoreName}}Store((state) => state.items);
* const loadItems = use{{StoreName}}Store((state) => state.loadItems);
*
* // Subscribe to changes outside React
* use{{StoreName}}Store.subscribe(
* (state) => state.selectedId,
* (selectedId) => console.log('Selected:', selectedId)
* );
* ```
*/
export const use{{StoreName}}Store = create<{{StoreName}}Store>()(
subscribeWithSelector((set, get) => ({
// Initial state
...initialState,
// Simple setters
setItems: (items) => set({ items }),
setSelectedId: (selectedId) => set({ selectedId }),
setLoading: (isLoading) => set({ isLoading }),
setError: (error) => set({ error }),
// Async action example
loadItems: async () => {
set({ isLoading: true, error: null });
try {
// const items = await fetchItems();
const items: unknown[] = []; // Replace with actual fetch
set({ items, isLoading: false });
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to load',
isLoading: false,
});
}
},
// Add item (immutable update)
addItem: (item) => {
set({ items: [...get().items, item] });
},
// Remove item (immutable update)
removeItem: (id) => {
set({
items: get().items.filter((item) => (item as { id: string }).id !== id),
// Clear selection if removed item was selected
selectedId: get().selectedId === id ? null : get().selectedId,
});
},
// Reset to initial state
reset: () => set(initialState),
}))
);
```