state-management
This skill provides patterns and best practices for managing state across frontend applications, covering local component state, global stores using Zustand or Pinia, server state caching with TanStack Query, and URL-based state management. Use it when architecting state solutions, deciding between local versus global state, implementing server data synchronization, or managing shareable state through router parameters in React and Vue applications.
git clone --depth 1 https://github.com/MadAppGang/claude-code /tmp/state-management && cp -r /tmp/state-management/plugins/dev/skills/frontend/state-management ~/.claude/skills/state-managementSKILL.md
# Frontend State Management
## Overview
Patterns and best practices for managing state in frontend applications across different frameworks.
## State Categories
### Local vs Global State
| Type | Scope | Examples | Solution |
|------|-------|----------|----------|
| **Local UI** | Single component | Form inputs, modals, dropdowns | useState, ref |
| **Shared UI** | Component subtree | Theme, sidebar state | Context, provide/inject |
| **Server** | Cached API data | Users, products, orders | TanStack Query, SWR |
| **Global App** | Entire app | Auth, settings, notifications | Zustand, Pinia, Redux |
| **URL** | Browser URL | Filters, pagination, search | Router params/query |
### When to Use What
```
┌─────────────────────────────────────────────────────────┐
│ Does only this component need it? │
│ YES → Local state (useState/ref) │
│ NO ↓ │
├─────────────────────────────────────────────────────────┤
│ Is it server data that needs caching/sync? │
│ YES → Server state library (TanStack Query) │
│ NO ↓ │
├─────────────────────────────────────────────────────────┤
│ Is it in the URL (shareable state)? │
│ YES → URL state (router) │
│ NO ↓ │
├─────────────────────────────────────────────────────────┤
│ Is it needed across unrelated components? │
│ YES → Global store (Zustand/Pinia) │
│ NO → Lift state up or Context │
└─────────────────────────────────────────────────────────┘
```
## Server State (TanStack Query)
### Basic Query Pattern
```tsx
// Define query
function useUsers(filters: UserFilters) {
return useQuery({
queryKey: ['users', filters],
queryFn: () => api.getUsers(filters),
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 30 * 60 * 1000, // 30 minutes
});
}
// Use in component
function UserList() {
const [filters, setFilters] = useState<UserFilters>({});
const { data, isLoading, error } = useUsers(filters);
if (isLoading) return <Spinner />;
if (error) return <Error message={error.message} />;
return <List items={data} />;
}
```
### Mutation Pattern
```tsx
function useCreateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateUserInput) => api.createUser(data),
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
// Usage
const createUser = useCreateUser();
await createUser.mutateAsync({ name: 'John', email: 'john@example.com' });
```
### Optimistic Updates
```tsx
function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: UpdateUserInput) => api.updateUser(data),
onMutate: async (newData) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['user', newData.id] });
// Snapshot previous value
const previous = queryClient.getQueryData(['user', newData.id]);
// Optimistically update
queryClient.setQueryData(['user', newData.id], (old: User) => ({
...old,
...newData,
}));
return { previous };
},
onError: (err, newData, context) => {
// Rollback on error
queryClient.setQueryData(['user', newData.id], context?.previous);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
```
## Global State (Zustand)
### Store Definition
```tsx
interface AppStore {
// State
theme: 'light' | 'dark';
sidebarOpen: boolean;
notifications: Notification[];
// Actions
setTheme: (theme: 'light' | 'dark') => void;
toggleSidebar: () => void;
addNotification: (notification: Notification) => void;
removeNotification: (id: string) => void;
}
export const useAppStore = create<AppStore>((set) => ({
theme: 'light',
sidebarOpen: true,
notifications: [],
setTheme: (theme) => set({ theme }),
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
addNotification: (notification) =>
set((state) => ({
notifications: [...state.notifications, notification],
})),
removeNotification: (id) =>
set((state) => ({
notifications: state.notifications.filter((n) => n.id !== id),
})),
}));
```
### Selectors for Performance
```tsx
// BAD: Re-renders on any store change
const { theme, notifications } = useAppStore();
// GOOD: Only re-renders when theme changes
const theme = useAppStore((state) => state.theme);
// GOOD: Multiple selectors with shallow comparison
const { theme, sidebarOpen } = useAppStore(
(state) => ({ theme: state.theme, sidebarOpen: state.sidebarOpen }),
shallow
);
```
### Computed/Derived State
```tsx
const useAppStore = create<AppStore>((set, get) => ({
notifications: [],
// Derived state as selector
unreadCount: () => get().notifications.filter((n) => !n.read).length,
// Or compute in selector
}));
// Usage with computed
const unreadCount = useAppStore((state) =>
state.notifications.filter((n) => !n.read).length
);
```
## Global State (Pinia for Vue)
```ts
export const useAppStore = defineStore('app', () => {
// State
const theme = ref<'light' | 'dark'>('light');
const sidebarOpen = ref(true);
const notifications = ref<Notification[]>([]);
// Getters (computed)
const unreadCount = computed(() =>
notifications.value.filter((n) => !n.read).length
);
// Actions
function setTheme(newTheme: 'light' | 'dark') {
theme.value = newTheme;
}
function toggleSidebar() {
sidebarOpen.value = !sidebarOpen.value;
}
return {
theme,
sidebarOpen,
notifications,
unreadCount,
setTheme,
toggleSidebar,
};
});
```
## URL State
### Search Params|
|
|
Common agent patterns and templates for Claude Code. Use when implementing agents to follow proven patterns for Tasks integration, quality checks, and external model invocation via claudish CLI.
YAML frontmatter schemas for Claude Code agents and commands. Use when creating or validating agent/command files.
XML tag structure patterns for Claude Code agents and commands. Use when designing or implementing agents to ensure proper XML structure following Anthropic best practices.
YAML format for Claude Code agent definitions as alternative to markdown. Use when creating agents with YAML, converting markdown agents to YAML, or validating YAML agent schemas. Trigger keywords - "YAML agent", "agent YAML", "YAML format", "agent schema", "YAML definition", "convert to YAML".
Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.