The React community has seen a number of different state management patterns emerging out over the last few years. They range from the very straight-forward setState API to the third-party libraries such as Redux and MobX(there are more, but these are the most widely used), and to the recently updated Context API.

Unstated is fairly a new library from @jamiebuilds that’s been gaining some momentum in the community. It leverages the power of React’s Context API to make state management extremely simple. How simple? The tagline of unstated is:

State so simple, it goes without saying.

After a few hours of working with it, I realized just how simple it is. The API is relatively small, and you can get up and run with it in a matter of minutes. This is a huge positive in a world where third-party state management solutions usually take considerable time to learn.





State management primer

Before getting started, let’s discuss why we’re really here in the first place. If you’re reading this post then chances are you’re either not happy with the existing solutions out there or you’re looking to try something different. So, let’s explore it.

React ships with its own internal state management solution, setState. It’s a straightforward API and a perfectly fine solution for most projects. Most, if not all React devs learn and use setState before anything else (as it should be), you will see many respected voices in the React community saying you not to use anything else until it’s absolutely necessary. I would largely agree.

But, eventually, you’ll hit some pain points. In my experience, these pain points are usually in the form of large state objects and event handlers defiling the components, along with the annoying “prop drilling” pattern that inevitably emerges when passing state down to child components.

This led us to libraries such as Redux and MobX, which abstract state management away from the component level while still allowing components to “subscribe” to any given piece of state. This mostly solves the problems I mentioned above with setState. Looking further, these libraries are hugely popular and well maintained. Wouldn’t it make sense to double down on one of them and never look back?

With great power comes great… boilerplate.

I’m sure there’s a larger discussion to be had about the pros and cons of these libraries, but I don’t want to stay too far off our intended path here. I do, however, think it’s important to mention the issue of boilerplate because it’s a real thing and something that has always stopped me about Redux in particular.

The code is verbose. The number of files (depending on project structure) you need to interact with just to make a change to a piece of state can be overwhelming. It’s easy to start a new project with good intentions only to find yourself confused by your own folder structure because there is no standard.

This is what eventually led me to try unstated.





Getting started

You can install unstated with yarn via yarn add unstated. From there, integrating it into your React application is a breeze. Like I mentioned before, the API is very small, exposing only 3 components:

import { Provider, Subscribe, Container } from 'unstated'





Provider

The Provider is very similar to the other Provider types existing in libraries like Redux. You use it at the highest level of your application necessary to provide state to specific components:

<Provider> <App /> </Provider>





Container

The Container is used when creating a “slice” of state. You use it in a similar way you would use React.Component:

class StateContainer extends Container { state = {} updateThis = () => { this.setState({}) } updateThat = () => { this.setState({}) } }





StateContainer will hold a piece of application state, along with any methods that exist to update that state. It’s a beautiful thing really, because everything is encapsulated together.

Notice the use of setState here in the handler methods. According to the official unstated docs:

setState() in Container mimics React’s setState() method as closely as possible.

This means that calling setState inside the Container will cause subscribed components to re-render! You can even use setState as a function:

this.setState( prevState => ({}) )





Subscribe

Now that you know how to create a state. But, how do you pass it to your components? This is where Subscribe comes in. It uses a render prop to pass state and methods into your components:

<Subscribe to={[StateContainer]}> {container => ( /* access container.state */ /* access container.updateThis() */ /* access container.updateThat() */ )} </Subscribe>

One interesting point to make about Subscribe is that the to prop takes an array. This gives you the ability to pass multiple state container instances into your components:

<Subscribe to={[StateContainer, OtherStateContainer]}> {(container, otherContainer) => /* */} </Subscribe>





An example

Now that we’ve gone over the entire API (yes, that’s essentially the entire API in a nutshell). Let’s walk through an example together, shall we? I’ve gone ahead and created a sample project here. The project uses create-react-app, styled-components