Lazy Ant Lab
engineering3/1/2026

State Management Without Libraries

State Management Without Libraries

Redux, MobX, Zustand... do you really need them? Often, React's built-in tools are enough. Let’s climb the state complexity ladder and see where your app actually lands.

Before reaching for an external state management library, every engineer should ask: "What problem am I actually solving?" In the modern React ecosystem, we often over-engineer before we even hit a bottleneck.

The State Complexity Ladder

Think of state as a ladder. You only move up when the current step can no longer support your weight:

  • Level 1: Local State

    • 🐜 Scope: Single component.

    • 🐜 Tool: useState or useReducer.

  • Level 2: Lifted State

    • 🐜 Scope: Parent and direct children.

    • 🐜 Tool: Prop drilling (it's not a crime, it's explicit).

  • Level 3: Context

    • 🐜 Scope: Cross-cutting concerns (Auth, Theme, i18n).

    • 🐜 Tool: useContext.

  • Level 4: External Library

    • 🐜 Scope: Complex async flows, heavy computed state, or time-travel debugging.

    • 🐜 Tool: Zustand, Redux, Jotai.

Most Apps Stop at Level 3

Context combined with custom hooks solves 90% of state management needs. Look at this clean Auth implementation:

TypeScript

// Clean, simple, no library.
const AuthContext = createContext<AuthState | null>(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  // Auth logic here...

  return (
    <AuthContext.Provider value={{ user, loading, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

When Do You Actually Need a Library?

Be honest with your architecture. Consider external tools only when:

  • You genuinely need time-travel debugging.

  • You have insane async flows with frequent race conditions.

  • Your state updates are highly interdependent and causing massive re-renders that memoization can't fix.

The Lazy Ant Approach

  1. Start with local state.

  2. Lift only when needed.

  3. Add context sparingly.

  4. Reach for libraries last.

Most complexity comes from over-engineering, not under-tooling.

Connect with the author:

Continue Reading —