Managing application state in React

By Julien Noleau on January 30, 2017

Nowadays, when we talk about state management, Redux is often the answer. But is it always relevant ?

I will not criticize Redux in this article, because it is a very good state manager, well documented with a simple Api but Redux is not simple. It separates 2 concepts, the Action - the cause - and the Reducer - the consequence -. This separation can be powerful but is often misunderstood and only creates in most cases a useless “indirection”. Please don’t use a library because everyone uses it (you should read this from Redux author). Before even trying to use a library you need to understand which problem it solves, and more importantly which problem you want to solve.

To go deeper into state management we are going to start from React alone and forget everything else. Do you remember your first React Component ?

Props VS State

That’s the first question we ask ourself. In a component what’s the difference between state and props?

Test button

With State

With Props

  • Each time the state is changed, the component is re-rendered;
  • Each time the props is changed, the component is re-rendered;

From the rendering point of view: it’s the same! The render process is just a function transforming state & props (props, state) => VDOM .The difference is not based on the renderer but on the component itself, the difference is about Responsability.

I have omitted the parent component <MyButtonContainer /> but in fact it contains the state if <MyButton /> does not:

The props are computed on a higher state in the component hierarchy. A stateful component is responsible to manage, to update its private local state.

A simple vision is to consider that props are read-only parameters while state is a private, local set of attributes.

So where does live the state?

Let’s create a very simple application: a month-year selector.

Month selector 1

I have one component including its state: the current month, but for UI reason I want to add a “prev” and “next” button.

Month selector 2

Ok I have a problem to solve, I need to refactor my previous component and pull up the state in a parent container. Something like this:

Month selector 3

Then I want to use this month in another part of my app to display the season associated with this month.

Month selector 4

I am in front of a recurring problem! Each time I add a feature on my application, I need to refactor my root component and pull up the state.

Another related problem is the callback props hell. Because I need the state on my top component, others components are not able to manage it, they are all stateless so we need a chain to pull up the user interactions. In this very simple example we have only a 3-levels tree but in a real app you might come up to lengthy chains, let alone the naming onChange -> onChange -> onChange -> onChange -> ...

Here we go, let’s try to solve this problem

If you focus on the root component you can see it is nothing more than a state manager. It has an attribute, the state, - the application state - which is our Model and it updates this model on interactions (pulled up by others), like a Controller! this is not exactly the role of React (our View), so a common idea is to separate this “M.C.”.

Separate the state manager

If I export only the state which is a plain object, nothing will happen because React needs an explicit setState to rerender the tree. I need something to turn the state into something observable: The Store. Then I have just to implement the Observer pattern with a generic component, listening to this store (this is the component hidden behind the connect function in react-redux).

Each time the state changes, the Store notifies its listeners, the <Connector /> does a setState and the magic happens.

Store

So I came up with a simpler version of Flux: the view connector or anything else in the env calls a function (we can call this function an “Action” but remember this is just a vanilla JS function), this function has direct access to the store Api setState and the store notifies its listeners (for example the view) each time the state has been modified.

Implementation of “Simplux”

The state manager I am describing - let’s call it Simplux - is really easy to implement. I could develop it from scratch but let’s leverage Redux (I would rather not reinvent the wheel and lose all the community effort around Redux and all the tools). Redux is in fact more generic than Simplux so a smarter way is to use Redux!

I only need to (re)implement the setState(state) function. Here is the idea:

The microlib can be found on npm npm i --save redux-simplux (source: https://github.com/jnoleau/simplux )