React State Management Cheat Sheet
Quick reference guide for Zustand & Redux Toolkit: Store creation, middleware, actions, selectors, and async thunks.
Modern Frontend
zustand
redux
state-management
State management libraries like Zustand and Redux Toolkit simplify managing global reactive application state across React components.
Zustand Store & Middleware Setup
typescript
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
interface UserState {
username: string;
theme: "light" | "dark";
setUsername: (name: string) => void;
toggleTheme: () => void;
}
export const useUserStore = create<UserState>()(
persist(
(set) => ({
username: "Guest",
theme: "dark",
setUsername: (name) => set({ username: name }),
toggleTheme: () => set((state) => ({ theme: state.theme === "dark" ? "light" : "dark" }))
}),
{
name: "user-storage",
storage: createJSONStorage(() => localStorage)
}
)
);
Redux Toolkit (`createSlice` & `createAsyncThunk`)
typescript
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
export const fetchUser = createAsyncThunk("user/fetch", async (id: number) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
});
const userSlice = createSlice({
name: "user",
initialState: { data: null, status: "idle" },
reducers: {
clearUser: (state) => {
state.data = null;
}
},
extraReducers: (builder) => {
builder.addCase(fetchUser.fulfilled, (state, action: PayloadAction<any>) => {
state.data = action.payload;
state.status = "succeeded";
});
}
});
Comparison Matrix
Table
| Feature | Zustand | Redux Toolkit |
|---|---|---|
| Boilerplate | Extremely low (single hook) | Low to Medium (createSlice) |
| Context Provider | Not required | Requires <Provider store={store}> |
| Selectors | Native atomic selectors (s => s.count) | useSelector((state) => ...) |
| DevTools | Built-in redux devtools middleware | Built-in native Redux DevTools support |
Common Pitfalls & Tips
[!WARNING] Selecting the entire Zustand store state without atomic selectors (e.g.,
useUserStore()) causes your component to re-render on any store state mutation!
[!TIP] Use atomic selectors in Zustand (e.g.
const name = useUserStore(s => s.username)) to limit re-renders strictly to required properties.