Zustand and localStorage Aren't Redundant — They Solve Two Halves of Auth State
Mixing persistence and reactive state is a common source of bugs in React auth flows. Treating localStorage as the durable layer and Zustand as the runtime layer eliminates stale UI and prop-drilling without over-engineering.
React components need to know whether a user is logged in, but localStorage alone won't trigger re-renders. Zustand provides a global store that any component can subscribe to, making auth state immediately reactive across the UI. The store initializes by reading persisted tokens from localStorage, then keeps the two layers synchronized on login and logout. The pattern separates concerns cleanly: localStorage survives refreshes, Zustand drives the live React state. A single `setAuth` call updates both the store and localStorage, and a `logout` action clears both, returning the app to an unauthenticated state.
Beginners often treat localStorage as the source of truth for auth, then wonder why the UI doesn't update — the missing piece is a reactive store that bridges persistence and rendering.
The Zustand create(set => ({})) pattern looks odd because it inverts control: you hand a factory function a setter, and Zustand wires up the subscription machinery behind the scenes.
Storing both a token and a parsed user object in the store is a pragmatic choice that avoids repeated deserialization and lets components consume identity data directly.