The Three Responsibilities of a Client-Side State Management Solution

Last updated Invalid date
State management is one of the most challenging parts of every application. No matter the approach used to solve it, the problems to be addressed are the same: storage, updating state, and enabling reactivity.

Historically, when starting on a new React project, we’ve had to design and implement the state management infrastructure from scratch in a bare-bones way.

No matter which approach we take, in every client-side application, the generic role of a state management solution is the same: to handle storage, update state, and enable Reactivity.

Client-side state management


Most apps need to hold onto some data. That data may contain a little slice of local state that we’ve configured client-side, or it could be a subset of remote state from our backend services.

Often, we need to combine these two pieces of data, local and remote, and then call upon them in our app at the same time. This task alone has the potential to get pretty complicated, especially when we need to perform updates to the state of our app.

Update state

The Command-Query Segregation Principle states that there are two generic types of operations we can perform: commands and queries.

In GraphQL, we refer to these as queries and mutations.

In REST, we have several command-like operations like delete, update, post, etc and one query-like operation called get.

Most of the time, after invoking an operation in a client-side web app, we need to update the state stored locally as a side-effect.


When storage changes, we need an effective way to notify pieces of our UI that relied on that particular part of the store, and that they should present the new data.

Each state management approach has a slightly different approach

Just about every library available out there right now can adequately handle all three of these responsibilities! Here are some of the most popular approaches right now in the React realm.

Client-side state management options


  • Storage: Plain JS object
  • Updating state: actions + reducers
  • Reactivity: Connect

React Context + Hooks

  • Storage: Plain JS object
  • Updating state: useReducer (or not)
  • Reactivity: useContext

Apollo Client

  • Storage: Normalized cache
  • Updating state: Cache APIs
  • Reactivity: (Auto) Broadcast change notifications to Queries


Liked this? Sing it loud and proud 👨‍🎤.

Stay in touch!

About the author

Khalil Stemmler,
Software Essentialist ⚡

I'm Khalil. I turn code-first developers into confident crafters without having to buy, read & digest hundreds of complex programming books. Using Software Essentialism, my philosophy of software design, I coach developers through boredom, impostor syndrome, and a lack of direction to master software design and architecture. Mastery though, is not the end goal. It is merely a step towards your Inward Pull.

View more in Software Design

You may also enjoy...

A few more related articles

Why I Recommend a Feature-Driven Approach to Software Design
Features represent the essential complexity of software design. It's the complexity that can't be avoided. Everything else — the l...
How I Write Testable Code | Khalil's Simple Methodology
The single biggest thing that improved the quality of my designs was understanding how dependencies influence my ability to write ...
Comparison of Domain-Driven Design and Clean Architecture Concepts
Eric Evans' "Domain-Driven Design" and Uncle Bob's "Clean Architecture" are books that have introduced tactical approaches towards...
How to Learn Software Design and Architecture | The Full-stack Software Design & Architecture Map
Software Design and Architecture is pretty much its own field of study within the realm of computing, like DevOps or UX Design. He...