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
FeatureZustandRedux Toolkit
BoilerplateExtremely low (single hook)Low to Medium (createSlice)
Context ProviderNot requiredRequires <Provider store={store}>
SelectorsNative atomic selectors (s => s.count)useSelector((state) => ...)
DevToolsBuilt-in redux devtools middlewareBuilt-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.