Article

What is state? Why do I need to manage it?

State management makes the state of your app tangible in the form of a data structure that you can read from and write to. It makes your ‘invisible’ state clearly visible for you to work with.

I remember when I wrote my first React app for work, in 2015. It was my first foray into really client-side JavaScript-heavy work.

Previously I had worked with JavaScript in a ‘sprinkles here, sprinkles there’ kind of way — bits and pieces for WordPress themes and plugins. In terms of JavaScript frameworks, I had only ever used a bit of jQuery. I was now faced with writing React!

Talking with developer friends and colleagues about the project, they all said the same thing.

“Oh yeah you’ll need a state management library — check out Flux or Redux”

I nodded and said okay and looked at the Github pages for Flux and Redux, but to be honest, I had no idea what these libraries did or why I would want to use one.

To manage my state, obviously.

The problem was… I had no idea what ‘state’ was, and I was too afraid to ask someone, because obviously it was something that everyone already knew, and I didn’t want to look stupid 🙄.

I’m going to assume that you (or your friend) also don’t know what state is, or why you need to manage it. Here’s some of the ways I like to think about it—maybe you’ll find this useful in building your understanding.

I mostly talk about React in this article, because that’s what I use most frequently, but the concepts are applicable across many JavaScript frameworks, and even in vanilla JS.

What is State?

When it comes to client-side JavaScript applications, I like to think of state as “the outcome of all of the actions that the user has taken since the page loaded”.

This isn’t an all-encompassing way of thinking about state, as other agents might affect state — the server might set some variables, a service worker might do something in the background, etc. However, I found it a useful place to start when I was building my understanding.

For example, I load a page. I click a button which makes an HTTP request. The HTTP request fails, and the screen now shows an error.

What is the action? A button was clicked, it sent off a request, and the request failed.

Whis is the outcome? An error message.

If we were to describe that state as an object, it might look like this:

const state = {
  errors: ["Sorry, we couldn't save your article, try again later"]
}

Of course, I would also show that error message on the screen.

If you’re used to working with smatterings of JavaScript, you might be familiar with handling the failure of an Ajax request and displaying the error on screen. What you might not be familiar with is actually storing the error in an object like I’ve done above.

This is where state management comes in

In both situations, the state is the same — there’s an error message. But when we manage our state, we create an explicit data structure (in my case, an object with a key named ‘errors’) to record the outcomes of the user’s actions.

State management libraries provide us with tools for creating these data structures, and updating them when new actions occur. For example, with Redux, your state is stored as a JavaScript object. With MobX, it’s stored as an Observable. If you use React’s component state, your state could be a string, or a number, or anything you like.

Without a state management system, how do we know what the state of our application is? We look at the DOM. We can check DOM elements to see if they have certain classes (‘active’, ‘error’), or to check whether certain elements exist.

With a state management system, to find out what the state of our application is, we check our state data structure. The DOM should reflect the data, but the data is the Source Of Truth.

Why would I want to use state management tools?

For me, the key to understanding state management was when I realised that there is always state. Whether or not I’m managing it, with an interactive web application, there is always state — users perform actions, and things change in response to those actions.

State management makes the state of your app tangible in the form of a data structure that you can read from and write to. It makes your ‘invisible’ state clearly visible for you to work with.

Rather than looking at the DOM and deducing state based on what is there and what is not, an explicit data structure is much easier to understand.

When you’re creating larger and more complex JavaScript applications, having explicit data to work with in a predictable way is a huge boon to developers. It’s much easier to reason about and manipulate, and it’s less bug-prone (though of course, you can still create a lot of bugs with any code you write with a state management system).

Some bonus benefits to understanding state management

Understanding the purpose of state management really changed how I think when I’m working with JavaScript, and on the whole, it made me a better developer.

Before working with JavaScript frameworks, I had never thought of the actions that a user makes as a holistic group of causes and effects. The way I had written JavaScript before, it was just a bunch of one-off operations that manipulated the DOM and may or may not have had any relation to each other.

I also never saw ‘state’ and the DOM as separate entities from each other — to me, they were the same thing. In the DOM, there is an error message, so the state is that there is an error message.

By separating out the data (there is an error message) from the effects (an error message is displayed on the screen), I found myself thinking about my code in a much more declarative way, which was extremely powerful as I learned more and took a a dive into functional programming.

Don’t worry if none of that makes sense to you in the beginning. It took me quite a while to really grok this!

That’s it!

I hope that gives you a bit of insight into how I think about state. It’s an incomplete view, but I think it’s a place to start when you’re first getting into complex client-side applications.