The Three Responsibilities of a Client-Side State Management Solution

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

Storage

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.

Reactivity

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

Redux

  • 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


Discussion

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


0 Comments

Be the first to leave a comment

Submit

Stay in touch!



About the author

Khalil Stemmler,
Developer Advocate @ Apollo GraphQL ⚡

Khalil is a software developer, writer, and musician. He frequently publishes articles about Domain-Driven Design, software design and Advanced TypeScript & Node.js best practices for large-scale applications.



View more in Software Design



You may also enjoy...

A few more related articles

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 it's own field of study within the realm of computing, like DevOps or UX Design. H...
The 6 Most Common Types of Logic in Large Applications [with Examples]
In this article, you'll learn about the Clean Architecture, why we should separate the concerns of large applications into layers,...

Want to be notified when new content comes out?

Join 5000+ other developers learning about Domain-Driven Design and Enterprise Node.js.

I won't spam ya. 🖖 Unsubscribe anytime.

Get updates