Overmind, the state management library you don’t know (yet) (but should)

Julien De Luca
4 min readApr 1, 2022

There are hundreds and hundreds of state management libraries around there. Every day on echojs, you can spot a new one.

This one uses proxies, this other atoms, oh and look, that one handles side effects too.

There is one though, that deserves to be known more. It’s called overmind.

What makes overmind so unique ?

Regarding state management, redux is king. But redux is bare bone, and you will quickly end up adding immutability, side effects handling, a selector library, action creators, and so on.

Redux-toolkit has been made to make things easier regarding all the boilerplate redux needs. But I personally find it bloated, and it adds a lot of complexity, hurts code readability, and is sometimes confusing because it overlaps some redux core functionality.

On the other hand, overmind aims at providing everything you need, with a simple API, and helps you produce a much less verbose code in the end.

What makes overmind so special is that it matches the way you think when you think about state flows, e.g. :

This action should first set some state as “loading”, then query the database, then set the value of state with the returned value, then set “loading” to false.

With redux, doing something that simple can quickly become very verbose, and you spend more time thinking how to figure the right redux way instead of focusing on your business logic.

Let’s not even talk about the bizarre “createAsyncThunk” and “extraReducers” APIs of redux-toolkit.

Overmind merges the concepts of state, actions, reducers and side effects in the same place, while keeping everything cleanly isolated.

How ?

  • State is directly mutable through a transparent proxy.
  • State has computed values.
  • Actions are first class citizens that get state, effects and context as parameters.
  • You can access the whole state from the actions.
  • Side effects are accessed using a unified API.
  • By using a proxy, selectors and memoization are not needed anymore: it automatically finds what part of the state is used in your component.

The gist

The idea is simple, you juste define actions, and these actions do what they should: do things.

There is no reducer, actions alone allow you to mutate the state, trigger other actions, and call a side effect :

Let’s explore the API in detail.

Config

You are free to organize code as you want, but usually you will want to split actions, effects and state :

Actions

Actions are several concepts merged into one. They are a mix between classic redux actions, thunk actions, reducer, and middleware.

An action can :

  • Mutate state
  • Trigger another action
  • Call a side effect
  • Be async

Let’s see an example action :

Here we mutate the state, call a side effect and mutate the state again. Straightforward.

Effects

To handle side effects, you need to wrap them in a normalized API. Then they are available through the “effects” argument.

Let’s see how we can implement a router side effect :

There is a special method called “onInitializeOvermind” that allows you to setup things. It’s an ideal place to initialize side effects :

Then for each route the corresponding action will be called :

About fetching data

One of the things you will want to implement in side effects is data fetching. Maybe you usually use apollo-client, or relay.

While these libraries are pretty advanced in their field, they introduce a lot of complexity in your app, and you will often face that moment when you will ask yourself how to integrate them with your state.

With overmind, you will probably find it refreshing to handle your queries yourself in a side effect, manually caching things instead of fighting that apollo cache we all hate (don’t we ?).

There is an official GraphQL addon, that covers the basics, but if you need polling or some advanced caching you’ll probably want to make your own. That may sound scary, but in reality it may be far easier than trying to make apollo and redux live together peacefully.

State

In overmind, the state is a global object. Slices are called “branches”, but they really are just object nesting.

As you can see you can define derived state values from the original state. You can also use this as getters and add an argument.

Components

Connecting components is really simple. Because overmind uses a proxy, you just access state inside of a component using a hook, and it will update only if that part of the state changes :

I found that using overmind, a lot of the stuff I was doing inside the components was moved to actions, and components end up being just wired to state and actions.

Devtools

All of this would be frustrating without a nice devtools extension. It’s really well done, features complete, and allows you to do what you’d expect it to do.

There is a lot more !

This was really just an overview. Overmind is batteries included, and includes advanced tools like state machines, models, pipe operators… And never feels bloated.

Go explore its docs, they are really well written, and give you a better idea of what you can achieve with overmind.

--

--

Julien De Luca

Javascript, React, CSS, HTML, Python, Docker, AWS, GraphQL and love. Cofounder and CTO of https://skillfab.io.