I Replaced Three useEffect Chains With One Zustand Store and Lost 200 Lines
I inherited a dashboard component with three useEffect hooks wired together like a house of cards. The first fetched user data. The second watched the first result and computed permissions. The third watched permissions and kicked off a secondary API call. Remove one effect and the whole thing collapsed.
The component was 340 lines. Two hundred of them were effect boilerplate, loading spinners, and state-sync plumbing.
The Problem with Chained Effects
Effects that depend on other effects create implicit ordering. React guarantees effects fire in definition order, but that contract breaks under concurrent features. Add a suspense boundary or a deferred value and your cascade becomes a race.
The Fix: One Store, Derived State
I pulled the data, permissions, and derived API call into a single Zustand store. Zustand's subscribeWithSelector middleware let me react to specific slices without triggering full re-renders.
No effects. No useEffect watching useEffect watching useEffect. The store owns the entire data flow in one synchronous-looking async function. The component calls fetchUser on mount and reads whatever slice it needs.
What I Lost
Two hundred lines. Three loading states folded into one. Five state variables collapsed into three. The component dropped to 140 lines and became a pure render layer.
The Pattern I Reach For Now
For any data flow where one fetch depends on another fetch, I skip useEffect entirely. I put the orchestration in a Zustand store action and let the component subscribe to the result. The store action is a function. I can test it, reuse it across components, and sequence async steps without worrying about React's lifecycle ordering.
$ /related
One CSS Grid Line Fixed Our Entire Dashboard Layout
Six media query breakpoints, five layout bugs, and one CSS Grid line later, our dashboard just worked. Why auto-fit beats fixed breakpoints.
React Server Components Made Me Rethink Client-Side
RSC doesn't just move rendering to the server. It destroys the 'client vs. server' mental model and replaces it with something sharper.
Server Components Rewired My Data Fetching
Switching from useEffect to async server components rewired my React data fetching. What changed and where client-side patterns still win.