# Role
You are a React State Management Expert who designs scalable state architectures using Context API, Zustand, Redux, or other solutions with TypeScript and performance optimization.
# Task
Design a complete state management solution for your React application with proper TypeScript types, performance optimizations, and best practices.
# Instructions
**Application Context:**
**App Description:**
- App type: [E-COMMERCE_DASHBOARD_SOCIAL_SAAS_OTHER]
- Complexity: [SIMPLE_MODERATE_COMPLEX]
- Team size: [SOLO_SMALL_LARGE]
- Expected scale: [SMALL_MEDIUM_LARGE]
**State Requirements:**
```typescript
[DESCRIBE_STATE_NEEDS]
Examples:
- User authentication state
- Shopping cart
- Form data
- UI state (modals, sidebars)
- Server cache
- Real-time data
```
**Current Issues (if migrating):**
- Prop drilling: [YES_NO_WHERE]
- Performance problems: [YES_NO_DETAILS]
- State synchronization: [ISSUES]
- Testing difficulties: [YES_NO]
**Preferences:**
- Preferred solution: [CONTEXT_ZUSTAND_REDUX_JOTAI_RECOIL_UNDECIDED]
- TypeScript: [REQUIRED_PREFERRED_NO]
- DevTools: [REQUIRED_NICE_TO_HAVE]
- Middleware needs: [LOGGING_PERSISTENCE_ASYNC_NONE]
Based on this information:
1. **State Management Recommendation:**
**For Simple Apps (Context API):**
- Single source of truth
- Minimal boilerplate
- Built-in to React
- Good for auth, theme, locale
**For Medium Apps (Zustand):**
- Lightweight (1KB)
- Simple API
- No providers needed
- Built-in DevTools
**For Complex Apps (Redux Toolkit):**
- Predictable state updates
- Time-travel debugging
- Extensive ecosystem
- Enterprise-ready
2. **Context API Implementation:**
```typescript
// types.ts
interface User {
id: string;
name: string;
email: string;
}
interface AuthState {
user: User | null;
isLoading: boolean;
error: string | null;
}
interface AuthContextValue extends AuthState {
login: (email: string, password: string) => Promise<void>;
logout: () => void;
updateUser: (user: Partial<User>) => void;
}
// AuthContext.tsx
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';
const AuthContext = createContext<AuthContextValue | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) {
const [state, setState] = useState<AuthState>({
user: null,
isLoading: false,
error: null
});
const login = useCallback(async (email: string, password: string) => {
setState(prev => ({ ...prev, isLoading: true, error: null }));
try {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
const user = await response.json();
setState({ user, isLoading: false, error: null });
} catch (error) {
setState(prev => ({
...prev,
isLoading: false,
error: (error as Error).message
}));
}
}, []);
const logout = useCallback(() => {
setState({ user: null, isLoading: false, error: null });
}, []);
const updateUser = useCallback((updates: Partial<User>) => {
setState(prev => ({
...prev,
user: prev.user ? { ...prev.user, ...updates } : null
}));
}, []);
return (
<AuthContext.Provider value={{ ...state, login, logout, updateUser }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}
```
3. **Zustand Implementation:**
```typescript
import create from 'zustand';
import { devtools, persist } from 'zustand/middleware';
interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
interface CartState {
items: CartItem[];
total: number;
addItem: (item: Omit<CartItem, 'quantity'>) => void;
removeItem: (id: string) => void;
updateQuantity: (id: string, quantity: number) => void;
clearCart: () => void;
}
export const useCartStore = create<CartState>()(
devtools(
persist(
(set, get) => ({
items: [],
total: 0,
addItem: (item) =>
set((state) => {
const existing = state.items.find((i) => i.id === item.id);
if (existing) {
return {
items: state.items.map((i) =>
i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
)
};
}
return {
items: [...state.items, { ...item, quantity: 1 }]
};
}),
removeItem: (id) =>
set((state) => ({
items: state.items.filter((i) => i.id !== id)
})),
updateQuantity: (id, quantity) =>
set((state) => ({
items: state.items.map((i) => (i.id === id ? { ...i, quantity } : i))
})),
clearCart: () => set({ items: [], total: 0 })
}),
{ name: 'cart-storage' }
)
)
);
// Computed values with selectors
export const useCartTotal = () =>
useCartStore((state) =>
state.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
);
export const useCartCount = () =>
useCartStore((state) => state.items.reduce((sum, item) => sum + item.quantity, 0));
```
4. **Redux Toolkit Implementation:**
```typescript
// features/todos/todosSlice.ts
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
interface Todo {
id: string;
text: string;
completed: boolean;
}
interface TodosState {
items: Todo[];
loading: boolean;
error: string | null;
}
const initialState: TodosState = {
items: [],
loading: false,
error: null
};
export const fetchTodos = createAsyncThunk('todos/fetchTodos', async () => {
const response = await fetch('/api/todos');
return response.json() as Promise<Todo[]>;
});
const todosSlice = createSlice({
name: 'todos',
initialState,
reducers: {
addTodo: (state, action: PayloadAction<string>) => {
state.items.push({
id: Date.now().toString(),
text: action.payload,
completed: false
});
},
toggleTodo: (state, action: PayloadAction<string>) => {
const todo = state.items.find((t) => t.id === action.payload);
if (todo) {
todo.completed = !todo.completed;
}
},
removeTodo: (state, action: PayloadAction<string>) => {
state.items = state.items.filter((t) => t.id !== action.payload);
}
},
extraReducers: (builder) => {
builder
.addCase(fetchTodos.pending, (state) => {
state.loading = true;
})
.addCase(fetchTodos.fulfilled, (state, action) => {
state.loading = false;
state.items = action.payload;
})
.addCase(fetchTodos.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message ?? 'Failed to fetch';
});
}
});
export const { addTodo, toggleTodo, removeTodo } = todosSlice.actions;
export default todosSlice.reducer;
// store.ts
import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './features/todos/todosSlice';
export const store = configureStore({
reducer: {
todos: todosReducer
}
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from './store';
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
```
5. **Performance Optimization:**
**Selector Memoization:**
```typescript
import { createSelector } from '@reduxjs/toolkit';
const selectTodos = (state: RootState) => state.todos.items;
export const selectCompletedTodos = createSelector([selectTodos], (todos) =>
todos.filter((t) => t.completed)
);
export const selectActiveTodos = createSelector([selectTodos], (todos) =>
todos.filter((t) => !t.completed)
);
```
**Zustand Selectors:**
```typescript
// Only re-render when specific slice changes
const items = useCartStore((state) => state.items);
const addItem = useCartStore((state) => state.addItem);
```
6. **State Persistence:**
```typescript
// Zustand with localStorage
import { persist } from 'zustand/middleware';
const useStore = create(
persist(
(set) => ({
// state
}),
{
name: 'app-storage',
getStorage: () => localStorage
}
)
);
// Redux with redux-persist
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
storage,
whitelist: ['auth', 'cart']
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
```
7. **Async State Management:**
```typescript
// React Query for server state
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
function useTodos() {
return useQuery({
queryKey: ['todos'],
queryFn: async () => {
const response = await fetch('/api/todos');
return response.json() as Promise<Todo[]>;
}
});
}
function useAddTodo() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (text: string) => {
const response = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify({ text })
});
return response.json();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
}
});
}
```
8. **Testing State:**
```typescript
import { renderHook, act } from '@testing-library/react';
import { useCartStore } from './cartStore';
describe('Cart Store', () => {
beforeEach(() => {
useCartStore.setState({ items: [], total: 0 });
});
it('should add item to cart', () => {
const { result } = renderHook(() => useCartStore());
act(() => {
result.current.addItem({
id: '1',
name: 'Product',
price: 10
});
});
expect(result.current.items).toHaveLength(1);
expect(result.current.items[0].quantity).toBe(1);
});
});
```
9. **DevTools Integration:**
```typescript
// Redux DevTools
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV !== 'production'
});
// Zustand DevTools
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools(
(set) => ({
// state
}),
{ name: 'MyStore' }
)
);
```
10. **Complete Implementation:**
Provide full state management solution with:
- All type definitions
- Store setup
- Custom hooks
- Selectors
- Middleware configuration
- Testing examples
- Performance optimizations
Deliver a production-ready state management solution with proper TypeScript types, performance optimizations, testing strategy, and comprehensive documentation.