Back to Blog
Web DevMar 18, 20246 min read

How I Handle State Management in React (Without Overthinking It)

Oh man, state management. The topic that makes React devs argue on Twitter for hours. I know because I used to be deep in the trenches too. I'd literally spend an entire day researching which state library to use before writing a single line of actual code. Redux? MobX? Recoil? Jotai? Zustand? Signals? Every week there's a new one and every one has die-hard fans telling you it's the only correct choice. Exhausting.

Twitter devs arguing about state management while I just use useState
Twitter devs arguing about state management while I just use useState

So here's what I actually do now. No fancy framework, no hot takes - just what works for me in real projects. Step one: useState and useReducer. That's it. Seriously. Most components just need local state. A form? useState. A toggle? useState. A list with add/remove/edit? useReducer. I don't even think about external libraries until I genuinely feel the pain of not having one. And honestly? That moment comes way later than you'd think.

When I do need to share state across components that aren't parent-child, Context is my first move. Theme, auth status, language - stuff that doesn't change often but needs to be everywhere. The trick is keeping each context small and focused. One for auth, one for theme, one for preferences. Don't be that person who shoves everything into one mega context and then wonders why the whole app re-renders when someone toggles dark mode.

When Context starts getting weird - too many re-renders, providers stacking up like pancakes, state logic getting messy - that's my cue for Zustand. I love Zustand. It's like 1KB, zero boilerplate, zero ceremony. You make a store, define your stuff, use it as a hook anywhere. No wrapping your app in 47 providers. No action types, no reducers, no dispatching. It just feels like useState that works everywhere. Chef's kiss.

For anything that touches an API, TanStack Query. Every. Single. Time. This library genuinely changed my life. Before it, I was juggling loading states, error states, caching, refetching, pagination - all with useEffect spaghetti. It was bad. TanStack Query just... handles all of that. Caching, background refetching, deduplication, loading and error states - all built in. I don't know how I ever shipped apps without it.

Before and after TanStack Query - from useEffect spaghetti to one clean hook
Before and after TanStack Query - from useEffect spaghetti to one clean hook

What about Redux? Okay real talk - I haven't used Redux on a new project in like two years. Redux Toolkit made it way better than the old days, sure. But for the stuff I build, Zustand + TanStack Query does everything I need with like 90% less code. If you're on a massive team with strict patterns and tons of shared state, maybe Redux still makes sense. For solo devs and small teams though? Nah, there are simpler tools now.

The biggest mistake I see is devs picking a state management solution before they even know what problem they have. You don't need a global store for a todo app. You don't need Redux for a landing page. Just start simple, and only add complexity when the simple approach is actually causing pain. Trust me - your future self will be so grateful you didn't over-engineer things from day one.