The Epic Journey from React State Management Despair to StateDream
🚨 The Irony That Started It All
We built StateDream to escape framework coupling. Yet here we are, about to integrate it into a Next.js app.
The bitter irony isn't lost on us. StateDream was born from React's limitations, yet we're using it in React anyway. Why? Because the real problem wasn't React—it was the architectural trap that every framework creates when business logic gets coupled to UI components.
This is the story of our journey. It's messy, it's real, and it captures the despair every frontend developer faces. But it also shows there's hope—and it doesn't require abandoning your framework of choice.
💔 Chapter 1: The Despair
It started innocently enough. We had a complex Next.js auction platform. Users could bid, sellers could list items, payments flowed through escrow. Nothing fancy—just a marketplace.
But as features grew, something broke. Our state management became... unmanageable.
// The horror we lived with
function AuctionComponent() {
  const [auction, setAuction] = useState<Auction | null>(null);
  const [bids, setBids] = useState<Bid[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  useEffect(() => {
    loadAuction(auctionId).then(setAuction).catch(setError);
  }, [auctionId]);
  useEffect(() => {
    if (auction) {
      loadBids(auction.id).then(setBids);
    }
  }, [auction]);
  // And then we needed to handle bid updates...
  useEffect(() => {
    const subscription = bidUpdates.subscribe((newBid) => {
      setBids(prev => [...prev, newBid]);
      // But wait, what about optimistic updates?
      // And what about error rollback?
      // And what about updating the auction status?
    });
    return () => subscription.unsubscribe();
  }, []);
  // Our component was now 200+ lines of state management spaghetti
}
The despair set in. E2E tests took 30+ seconds. Flake rates hit 70%. Development slowed to a crawl. We were spending more time debugging state synchronization than building features.
🤔 Chapter 2: The Search for Salvation
Like every good developer, we went shopping. "Surely someone solved this," we thought.
Round 1: Zustand - The Initial Hope
We loved Zustand. It was simple. No boilerplate. Just stores and hooks.
// Zustand looked so clean
const useAuctionStore = create((set, get) => ({
  auction: null,
  bids: [],
  loadAuction: async (id) => {
    const auction = await api.getAuction(id);
    set({ auction, bids: [] });
    get().loadBids(id);
  },
  loadBids: async (id) => {
    const bids = await api.getBids(id);
    set({ bids });
  }
}));
But then we tried to test it. Our E2E tests still needed to click through login flows, create auctions, place bids. Tests were slow and flaky.
The despair deepened. "Why can't I just set the app state directly for testing?"
Round 2: Redux - The Enterprise Solution
We tried Redux. It was powerful. Actions, reducers, middleware. Surely this would scale.
But the boilerplate was crushing. 50 lines of code for a simple async operation? And we still couldn't test easily.
// Redux for a simple API call
const FETCH_AUCTION = 'FETCH_AUCTION';
const FETCH_AUCTION_SUCCESS = 'FETCH_AUCTION_SUCCESS';
const FETCH_AUCTION_ERROR = 'FETCH_AUCTION_ERROR';
const fetchAuction = (id) => async (dispatch) => {
  dispatch({ type: FETCH_AUCTION });
  try {
    const auction = await api.getAuction(id);
    dispatch({ type: FETCH_AUCTION_SUCCESS, payload: auction });
  } catch (error) {
    dispatch({ type: FETCH_AUCTION_ERROR, error });
  }
};
const auctionReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_AUCTION:
      return { ...state, loading: true };
    case FETCH_AUCTION_SUCCESS:
      return { ...state, loading: false, auction: action.payload };
    case FETCH_AUCTION_ERROR:
      return { ...state, loading: false, error: action.error };
    default:
      return state;
  }
};
More despair. This was supposed to be the solution? We were writing more infrastructure than business logic.
Round 3: The Framework Coupling Realization
Then came the Next.js moment. We tried using our Zustand stores in server components.
// This doesn't work in server components
import { useAuctionStore } from '@/stores/auctionStore';
export default function AuctionPage() {
  const { auction, loadAuction } = useAuctionStore(); // ❌ Can't use hooks here
  // ...
}
The real despair hit. We were forced to make every page a client component. Our beautiful server-side rendering? Gone. Our performance optimizations? Compromised.
"Why does state management force architectural compromises?" we asked.
That's when we realized: Every existing solution couples business logic to UI frameworks.
🔍 Chapter 3: The Architectural Discovery
We stepped back. Instead of "What's the best React state management?", we asked: "What's the actual problem we're solving?"
The answer shocked us: Business logic was trapped inside UI components.
// The problem wasn't state management - it was this coupling
function AuctionComponent() {
  // UI concerns
  const [uiState, setUiState] = useState();
  // Business logic mixed with UI
  useEffect(() => {
    if (paymentStatus === 'paid') {
      updateInventory().then(() => sendEmail()).then(() => clearCart());
    }
  }, [paymentStatus]); // Manual dependency management
}
This coupling created:
- Testing nightmares: Had to render components to test business logic
 - Framework lock-in: Business logic depended on React hooks
 - Complex synchronization: Manual 
useEffectchains everywhere - Race conditions: Async operations fighting for UI state
 
The insight was revolutionary: The problem wasn't state management—it was architectural. Business logic belonged in a separate layer, independent of UI frameworks.
🚀 Chapter 4: The StateDream Epiphany
We needed stores that:
- Work everywhere - React, Vue, Svelte, vanilla JS, server components
 - Test directly - Set state without UI interactions
 - Extract business logic - Move workflows out of components
 - Simple API - One-liners for 90% of cases
 
We started with RxJS. It had the reactive primitives we needed, but was too low-level.
Then we discovered Effector. It had framework-agnostic stores and event-driven effects. But it still required framework-specific bindings.
The breakthrough: Combine RxJS's power with simple, magical APIs.
// The dream DX we created
const auctionStore = createApiStore<Auction>({
  endpoint: '/api/auctions',
});
// That's it. One line.
// Auto-loading, error handling, optimistic updates, caching - all built-in
And for testing:
// Direct state manipulation - no UI required
auctionStore.setState({ id: 1, status: 'active' });
expect(someBusinessLogic()).toBe(expectedResult);
And for business logic:
// Flows - business logic lives where it belongs
createFlow()
  .when(auctionStore.state$.pipe(map(a => a.status === 'ended')))
  .then(() => processPayment())
  .then(() => notifyWinner())
  .catch(() => handlePaymentFailure());
This was the solution we needed. Not another state management library, but the architectural fix for the coupling problem.
🎯 Chapter 5: The Irony and the Truth
Here's the irony: We're integrating StateDream into a Next.js app. Despite building it to escape framework coupling, we're using it in React anyway.
But that's the point. StateDream doesn't force you to abandon your framework. It gives you the freedom to use it when you want, and escape when you need to.
- Want server components? Use StateDream stores directly.
 - Want client components? Use the optional React bindings.
 - Want to migrate to Vue? Your business logic stays the same.
 - Want to test? Set state directly, no UI rendering required.
 
🎪 Chapter 6: The Solution Every Frontend Dev Craves
StateDream isn't about React vs Vue vs Svelte. It's about this fundamental truth:
Frontend development shouldn't be a compromise between tooling, dependencies, and product quality.
You shouldn't have to:
- Choose between good DX and framework freedom
 - Settle for inferior products because they "fit your stack"
 - Rewrite business logic when migrating frameworks
 - Spend more time testing infrastructure than business logic
 
Life should be simple and made for achieving, not struggling.
StateDream is the answer. It's the library that gives you everything:
- ✅ Framework freedom without compromises
 - ✅ One-liner APIs for 90% of cases
 - ✅ Direct testing without UI rendering
 - ✅ Business logic extraction from components
 - ✅ Zero configuration, works everywhere
 
🌟 The Revolution Starts Now
We're not asking you to abandon React. We're asking you to stop compromising.
Try StateDream. Experience what frontend development feels like when you don't have to fight your tools.
The revolution isn't about frameworks. It's about freedom.
StateDream is available now. Install it, try it, and tell us: "Why did we wait so long?"
Links:
This journey doesn't have to be yours. The solution exists. Use it.