Why Query, Mutation, and Stream Need Different State Models
Query, Mutation, and Stream often get flattened into the same setState pipeline. Here's why treating them as one causes state confusion in frontend apps.
Frontend codebases often treat every async result the same way: resolve a promise, call setState, re-render. This piece argues that Query, Mutation, and Stream are semantically distinct kinds of work, and flattening them into one pipeline is a major source of state confusion.
A Query is about reading an identifiable data fact — it needs identity, caching, and revalidation, and should live as a resource node in a reactive graph rather than as ad-hoc component state. A Mutation's real difficulty isn't sending the request but declaring which existing data becomes invalid once it succeeds; scattering that invalidation logic across components creates a system where the mutation's impact is global but its handling stays local. A Stream is a long-lived data relationship concerned with connection health, backpressure, and the distinction between a current value and a stable value — concepts a single Promise or setState call can't express.
The core argument: once these three are collapsed into 'async work resolved → update state → render,' engineers lose the ability to answer basic questions about their own system — whether a loading state belongs to a query or a mutation, or whether a value is stable or mid-stream. Separating them by identity, invalidation, and lifecycle restores that missing boundary.