React State Management: When To Use Redux And What Are The Alternatives
Tags: react, redux, statemanagement, javascript
Published: 2020-03-19 18:21:54

When writing applications with react you will soon reach a point where you pass down callback functions as props two or three levels, to change the parents state. For most projects you will need a third party solution for global state management, so you can directly access and modify state from any component in your app, without passing callbacks down the DOM.

Redux has somewhat become the industry standard. However, it includes quite some boilerplate for every simple state change. Although I have to admit the situation feels better now with the introduction of hooks, it is still hard for beginners to wrap their head around the concepts. During the learning experience the question comes up: Why would we do it like this? Isn't there a simpler way? There actually is. More on that later.

I don't want to bash redux here. It is industry leader for a reason and has its strengths. But once you have worked with Vue and Vuex, most people realise it just feels much more intuitive. This is just one of the reasons why vue is growing so rapidly and just recently got more stars than react on github.

So before we go over some of the alternatives, let's first take a step back and have a look at what redux does and what it is good for.

# When To Use Redux

Redux is a global state management solution for frontend applications based around the idea of reducers. Reducers are pure functions, which take the previous state and action object, containing a type and an payload, to mutate the state. The action objects are also pure functions. This is already one thing, where many newcomers are scratching their heads.

Without going more into detail here, this approach has two main advantages.

## First: Global State Becomes Testable

You can now test your state completely isolated from your components. You import the reducer and the action into your test file. Since they are pure functions they have no dependencies whatsoever. You can than define a initial state object and pass it to the reducer, together with an action object. This way you can verify that a certain action mutates the state correctly without ever mounting a component. Since the state logic is tested already, all you have to do in the components, is to ensure that certain actions trigger the dispatch function with the correct action object. The dispatch function does not really have to executed and can be mocked.

## Second: Global State Becomes Easy To Debug

Since all your state mutations pass through a reducer and the passed action object contains information about what has to be changed and how, it is easy to track state changes. If you would mutate state directly and at some point wonder, why the state looks like it looks, you will have a hard time debugging, since the change could come from anywhere. With redux, you can move the debugger or logger into the reducer and observe each and every action of the state.

So redux definitely has it's advantages and especially shines in large scale projects where many programmers work on the same codebase and where we have big, deeply nested states. 

# When Not To Use Redux

Still, having to add an action function, modify the reducer and then connecting the component to toggle a boolean value, just does not feel natural and especially for small scale projects and prototypes probably is just overkill. But also for large scale projects there are alternatives. Let's have a look.

## Alternative: [Reactn](https://github.com/CharlesStover/reactn)

> ReactN is a extension of React that includes global state management. It treats global state as if it were built into React itself -- without the boilerplate of third party libraries.

Damn that sounds amazing. Initializing the global state works as follows:

{% gist https://gist.github.com/oshell/dd32d1a22b7ca059b9043e69a161b78a %}

With reactn you can simply refer to `this.global` instead of `this.state` and `this.setGlobal` instead of `this.setState` and you are done. `setGlobal` can even handle async data.

{% gist https://gist.github.com/oshell/e03006bd0c62aa87d0aa4901847708f8 %}

Using hooks? No Problem.

{% gist https://gist.github.com/oshell/27b5fcc2d613761bd515ca5c0a67f3a4 %}

For most people this approach should be much easier to handle, since it mirrors reacts default behaviour.

With reactn you can even use redux developer tools. Depending on your state, your app probably re-renders too often. But even then you can make use of `withGlobals` HOC and fallback to a redux like approach, similar to `mapStateToProps`. But you can do it where and when it is needed.

## Alternative: [Pullstate](https://github.com/lostpebble/pullstate)

Pullstate has similar syntax. However, it has no support for class components. It only delivers a third party hook for global state management. 

### Initializing Global State

{% gist https://gist.github.com/oshell/8f7ea3e0cf7dd6b996a359076dca1f9c %}

You can define as many stores as you want and they would be completely seperate.

### Reading Global State

{% gist https://gist.github.com/oshell/575d19a10c78e5085c6548c994cc69ce %}

To access values from the state, you call `useState` on your imported store and pass a reducer function as callback. The `s` here is the complete store and you simply return the value, you want to access.

### Mutate Global State

{% gist https://gist.github.com/oshell/b7bc63de262f9423668b3b64ab19a083 %}

## Alternative [Mobx](https://mobx.js.org/README.html)

How could I not mention Mobx here? The previous libraries where quite small and you do not know for sure for how long they are maintained. However, they also have quite small footprint and for most projects they will speed up initial development time a lot. However, if you want an actively maintained third party state management library, which is ready for large scale production apps and still want to avoid using redux, mobx is one of very few options.

{% gist https://gist.github.com/oshell/b04de6262daa6b95b2f65ac54eb801d3 %}

So with Mobx you basically depend on other third party libs, like `mobx-react-lite`, similar to 'react-redux'. You have to wrap your components in a `observer` function and use `useObservable` to initialise. Afterwards you can modify the store directly to trigger re-renders. To make it global you would have to define the store outside of the components and pass it into it via props.