The official state management tier list

Pavel Stanoev
June 22, 2025
4 views
6 min read
#React#State Management#Zustand#Jotai
Last updated: June 22, 2025

React developers have convinced themselves that managing state is rocket science. We've built entire careers around Redux boilerplate and Context API "best practices." But here's the thing: you're probably overthinking it.

The State Management Tier List

Let me rank the popular approaches from "actually good" to "why are you doing this to yourself":

🏆 S-Tier: URL State (The GOAT)

Your URL is the most underrated state management tool. It's persistent, shareable, and works with the back button. Revolutionary stuff.

// Instead of this Redux ceremony:
const dispatch = useDispatch();
const filters = useSelector((state) => state.filters);

// Just do this:
const searchParams = useSearchParams();
const category = searchParams.get("category") || "all";
// Yeah, yeah I know, Next.js...

Why it's amazing:

  • Users can bookmark your app state (mind = blown)
  • Survives page refreshes (unlike your Redux store)
  • On second thought - why are you refreshing your page? That's goddamn weird
  • SEO loves it
  • Zero setup, zero boilerplate
  • Debugging = look at the URL

🥈 A-Tier: Props Drilling (The Misunderstood Hero)

"But the Udemy course that I got from my free company account says that props drilling is bad!" - Developer who's never actually tried it

// This is supposedly "terrible":
function App() {
  const [user, setUser] = useState(null);
  return <Header user={user} onLogout={() => setUser(null)} />;
}

function Header({ user, onLogout }) {
  return <UserMenu user={user} onLogout={onLogout} />;
}

What's actually wrong with this? Nothing. It's:

  • Explicit (you can see where data flows)
  • Fast (no context re-render hell)
  • Easy to test (just pass props)
  • Zero setup
  • TypeScript loves it

Props drilling becomes a problem at 6+ levels deep. Until then, it's just... props. Thinking more about it - even then it's fine. I think I'm in love with props.

🥉 B-Tier: Zustand & Jotai (The Reasonable Choices)

When you actually need global state, these are solid:

// Zustand - Redux without the ceremony
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

// Jotai - Atomic and clean
const countAtom = atom(0);
const [count, setCount] = useAtom(countAtom);
  • Zustand pros: Tiny bundle, no providers, great DX
  • Jotai pros: Fine-grained updates, atomic state
  • Both: Way better than Redux/Context

🤡 D-Tier: Context API (The Footgun)

Context is for theming and auth - stuff that rarely changes. Using it for frequently updating state is like using a sledgehammer to crack an egg.

// This will re-render your entire app:
const AppContext = createContext();
const [state, setState] = useState({ user, cart, filters, theme });

Use Context only when:

  • The value changes rarely (theme, auth)
  • You're okay with performance issues
  • You enjoy debugging mysterious re-renders

💩 F-Tier: Redux (The Legacy Monster)

Redux is what happens when you take a simple problem and make it enterprise-grade complicated.

// Want to toggle a boolean? Here's your 47-step process:
const TOGGLE_MODAL = "TOGGLE_MODAL";
const toggleModal = () => ({ type: TOGGLE_MODAL });
const modalReducer = (state = false, action) => {
  switch (action.type) {
    case TOGGLE_MODAL:
      return !state;
    default:
      return state;
  }
};
// ... 200 more lines of boilerplate

Only use Redux if:

  • It's already in your codebase and removing it would take months
  • You enjoy writing 10x more code for simple tasks
  • You miss the good old days of Java enterprise development

PS: I write my Redux code deliberately worse than I'm supposed to, so you're easier to convince that this approach is wrong ;). What are you gonna do, report me to the Redux police? It's my blog, I'll strawman Redux all I want.

The Decision Tree (AKA "How to Not Overthink It")

Here's my foolproof method for choosing state management:

Step 1: Can it live in the URL?

If your state affects what the user sees and should be shareable/bookmarkable, put it in the URL.

Step 2: Is it just 2-3 components?

Use props drilling. Seriously. It's not that bad.

Step 3: Is it server data?

Use SWR or React Query. Don't reinvent caching.

Step 4: Do you actually need global state?

Fine, use Zustand or Jotai. But ask yourself twice.

Step 5: Are you being forced to use Redux?

My condolences. At least you're getting paid.

Common Objections (And Why You're Wrong)

"Props drilling is unmaintainable!" You're drilling through 8 components. That's not a props problem, that's an architecture problem. Refactor your components.

"URL state is ugly!" So is your Redux boilerplate. At least URLs are functional.

"What about performance?" Props drilling is faster than Context re-renders. URL updates are faster than Redux dispatches. You're optimizing the wrong thing.

"My team won't understand it!" Your team understands URLs and function parameters. If they don't understand props drilling, maybe the problem isn't the pattern.

The Bottom Line

Stop overthinking state management. Most React apps need exactly zero state management libraries. The web platform + React's built-in tools handle 90% of use cases.

Your app doesn't need to be enterprise-grade. It needs to work.