| name | state-management |
| description | Implement state management patterns for frontend applications. Use when managing global state, handling complex data flows, or coordinating state across components. Handles React Context, Redux, Zustand, Recoil, and state management best practices. |
| metadata | {"tags":"state-management, React, Redux, Context, Zustand, Recoil, global-state","platforms":"Claude, ChatGPT, Gemini"} |
State Management
When to use this skill
- Global State Required: Multiple components share the same data
- Props Drilling Problem: Passing props through 5+ levels
- Complex State Logic: Authentication, shopping cart, themes, etc.
- State Synchronization: Sync server data with client state
Instructions
Step 1: Determine State Scope
Distinguish between local and global state.
Decision Criteria:
Example:
function SearchBox() {
const [query, setQuery] = useState('');
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => setIsOpen(true)}
/>
{isOpen && <SearchResults query={query} />}
</div>
);
}
const { user, logout } = useAuth();
Step 2: React Context API (Simple Global State)
Suitable for lightweight global state management.
Example (Authentication Context):
import { createContext, useContext, useState, ReactNode } from 'react';
interface User {
id: string;
email: string;
name: string;
}
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
isAuthenticated: boolean;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const login = async (email: string, password: string) => {
const response = (, {
: ,
: { : },
: .({ email, password })
});
data = response.();
(data.);
.(, data.);
};
= () => {
();
.();
};
(
);
}
() {
context = ();
(!context) {
();
}
context;
}
Usage:
function App() {
return (
<AuthProvider>
<Router>
<Header />
<Routes />
</Router>
</AuthProvider>
);
}
function Header() {
const { user, logout, isAuthenticated } = useAuth();
return (
<header>
{isAuthenticated ? (
<>
<span>Welcome, {user!.name}</span>
<button onClick={logout}>Logout</button>
</>
) : (
<Link to="/login">Login</Link>
)}
</header>
);
}
Step 3: Zustand (Modern and Concise State Management)
Simpler than Redux with less boilerplate.
Installation:
npm install zustand
Example (Shopping Cart):
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
interface CartStore {
items: CartItem[];
addItem: (item: Omit<CartItem, 'quantity'>) => void;
removeItem: (id: string) => void;
updateQuantity: (id: string, quantity: number) => void;
clearCart: () => void;
total: () => number;
}
export const useCartStore = create<CartStore>()(
devtools(
persist(
(set, get) => ({
: [],
: ( {
existing = state..( i. === item.);
(existing) {
{
: state..(
i. === item.
? { ...i, : i. + }
: i
)
};
}
{ : [...state., { ...item, : }] };
}),
: ( ({
: state..( item. !== id)
})),
: ( ({
: state..(
item. === id ? { ...item, quantity } : item
)
})),
: ({ : [] }),
: {
{ items } = ();
items.( sum + item. * item., );
}
}),
{ : }
)
)
);
Usage:
function ProductCard({ product }) {
const addItem = useCartStore(state => state.addItem);
return (
<div>
<h3>{product.name}</h3>
<p>${product.price}</p>
<button onClick={() => addItem(product)}>
Add to Cart
</button>
</div>
);
}
function Cart() {
const items = useCartStore(state => state.items);
const total = useCartStore(state => state.total());
const removeItem = useCartStore(state => state.removeItem);
return (
<div>
<h2>Cart</h2>
{items.map(item => (
{item.name} x {item.quantity}
${item.price * item.quantity}
removeItem(item.id)}>Remove
))}
Total: ${total.toFixed(2)}
);
}
Step 4: Redux Toolkit (Large-Scale Apps)
Use when complex state logic and middleware are required.
Installation:
npm install @reduxjs/toolkit react-redux
Example (Todo):
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
interface Todo {
id: string;
text: string;
completed: boolean;
}
interface TodosState {
items: Todo[];
status: 'idle' | 'loading' | 'failed';
}
const initialState: TodosState = {
items: [],
status: 'idle'
};
export const fetchTodos = createAsyncThunk('todos/fetch', async () => {
const response = await fetch('/api/todos');
return response.json();
});
const todosSlice = createSlice({
name: 'todos',
initialState,
reducers: {
addTodo: (state, action: PayloadAction<string>) => {
state.items.push({
: .().(),
: action.,
:
});
},
: {
todo = state..( t. === action.);
(todo) {
todo. = !todo.;
}
},
: {
state. = state..( t. !== action.);
}
},
: {
builder
.(fetchTodos., {
state. = ;
})
.(fetchTodos., {
state. = ;
state. = action.;
})
.(fetchTodos., {
state. = ;
});
}
});
{ addTodo, toggleTodo, removeTodo } = todosSlice.;
todosSlice.;
{ configureStore } ;
todosReducer ;
store = ({
: {
: todosReducer
}
});
= < store.>;
= store.;
Usage:
import { Provider } from 'react-redux';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<TodoApp />
</Provider>
);
}
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../store';
import { toggleTodo, removeTodo } from '../store/todosSlice';
function TodoList() {
const todos = useSelector((state: RootState) => state.todos.items);
const dispatch = useDispatch();
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type=
=
= => dispatch(toggleTodo(todo.id))}
/>
{todo.text}
dispatch(removeTodo(todo.id))}>Delete
))}
);
}
Step 5: Server State Management (React Query / TanStack Query)
Specialized for API data fetching and caching.
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
function UserProfile({ userId }: { userId: string }) {
const queryClient = useQueryClient();
const { data: user, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: async () => {
const res = await fetch(`/api/users/${userId}`);
return res.json();
},
staleTime: 5 * 60 * 1000,
});
const mutation = useMutation({
mutationFn: async (updatedUser: Partial<User>) => {
const res = await fetch(`/api/users/${userId}`, {
method: 'PATCH',
body: JSON.stringify(updatedUser)
});
return res.json();
},
: {
queryClient.({ : [, userId] });
}
});
(isLoading) ;
(error) ;
(
);
}
Output format
State Management Tool Selection Guide
Recommended tools by scenario:
1. Simple global state (theme, language)
→ React Context API
2. Medium complexity (shopping cart, user settings)
→ Zustand
3. Large-scale apps, complex logic, middleware required
→ Redux Toolkit
4. Server data fetching/caching
→ React Query (TanStack Query)
5. Form state
→ React Hook Form + Zod
Constraints
Required Rules (MUST)
-
State Immutability: Never mutate state directly
state.items.push(newItem);
setState({ items: [...state.items, newItem] });
-
Minimal State Principle: Do not store derivable values in state
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);
const [items, setItems] = useState([]);
const count = items.length;
-
Single Source of Truth: Do not duplicate the same data in multiple places
Prohibited Rules (MUST NOT)
-
Excessive Props Drilling: Prohibited when passing props through 5+ levels
- Use Context or a state management library
-
Avoid Making Everything Global State: Prefer local state when sufficient
Best practices
-
Selective Subscription: Subscribe only to the state you need
const items = useCartStore(state => state.items);
const { items, addItem, removeItem, updateQuantity, clearCart } = useCartStore();
-
Clear Action Names: update → updateUserProfile
-
Use TypeScript: Ensure type safety
References
Metadata
Version
- Current Version: 1.0.0
- Last Updated: 2025-01-01
- Compatible Platforms: Claude, ChatGPT, Gemini
Related Skills
Tags
#state-management #React #Redux #Zustand #Context #global-state #frontend
Examples
Example 1: Basic usage
Example 2: Advanced usage