Goodbye Redux! I have a preferer immutable react state manager

frustigor

frustigor

Posted on September 9, 2020

Goodbye Redux! I have a preferer immutable react state manager

I have used react and react-redux for a long time. During last 2 years, I found it is so complex when I want to find out a single data flow from a dispatcher to usage through over than 5 files that I am now boring with redux's reducer and sync operation which makes async operation evil. I have been thinking about building my own react global state manager and finally I built a library react-immut to implement my goal.

State data flow

In the ecology of react, we advocate one way data flow and immutable state circulation. In ideal, our state flow is like this:

react state flow

However, UX handler will push data back, so it comes to be a circle like this:

react state circle flow

Each time we want to update a component's props, we will propagate the event back to the root parent to change the parent's state to trigger UI rerender. This make nested components full of no-use-pipe props.

To make it more convenient, react offical propose flux architecture which guide us to build global state manager. Redux (react-redux) become the most popular global state manager. The state data flow pattern switch to crossing components' level like this:

redux store manager

Global state manager make it much more clear in deep nested components net. Every 2 components no matter how many levels space are there between them, they can communicate with each other by two step with redux as a middleman.

Evil Reducer

The time in which reducer was treated as a angel has past, along with code increasing, redux reducer and action functions make us headache. Why should I write so much non-real-related code? Our purposes is to finish UI building more quickly, but redux slow us down like a stumbling block. And when I debug, I have to jump amoung files to find out why the data has changed to make error. If you give me a knife, I will pass it to redux.

Let's look into what we will have in redux+react system:

Alt Text

Yes, we get one way data flow, but we have to code here, here and here...

Alt Text

And I must combine these all parts together and must make them work well without any error.

Too many parts cause fragility!

In fact, I do want to focus on business components' dev.

Diehard Immutable

To ensure my state change as immutable, I have grown to be a player of object-spread(...). Let's look into a case:

Alt Text

Eumm... Why should I write so many ... and have to create such a deep nested repeated object?

Magician Immer

Immer is a library which help developers to immutablly modify object. It is amazing that it provides only one API produce function:

import produce from 'immer'

And the typical usage is:

const next = produce(prev, draft => {
  draft.root.parent.child[1].name = 'new name'
})

In the second parameter, it looks like a mutable operation, but in fact, it is just a draft, the output next is a new object which is from prev.

From now on, I will drop object-spread operation thanks for immer, easy, clear and magic.

New Generation

React hooks is a new way to penetrate nested components net. React-redux has provided a useSelector hook function to get state from global store. useContext give us a chance to siphon from top context. useReducer is a sample plate for use to use [state, dispatch] pattern in local scope.

Generation 2 global state management

Generation 2 global state management is based on hooks. You may hear the new state manager Recoil which is published by a facebook team. In recoil, state and actions are abstract as atoms, selectors.

Decent ReactImmut

I costed a weekend to finish a library react-immut which is a global state manager and has similar API as react-redux but without reducers. Let's look into a glance:

import { createStore, Provider, useStore } from 'react-immut'

const store = createStore({
  name: 'tom',
  age: 10,
})

function App() {
  return (
    <Provider store={store}>
      <div class="container">
        <h3>Some Person</h3>
        <Person />
      </div>
    </Provider>
  )
}

function Person() {
  const [state, dispatch] = useStore()
  const { name, age } = state
  const grow = () => dispatch(state => {
    // here `state` is a draft of global state
    state.age ++
  })
  return (
    <div>
      <span>Name: {name}</span>
      <span>Age: {age} <button onClick={grow}>Grow</button></span>
    </div>
  )
}

Look, isn't is easy? We have no need to define reducers, and has a powerful dispatch which is based on immer and make state change clear, convenient and comfortable.

This is a typical usage of react-immut, you can learn more from repo. If you think this is cool, give me a star!

Summary

We have experienced crossing props state management, global middleman state management and now we are using hooks to manage our state (global or local). We have followed immutable (redux) and mutable (mobx) dispatching, and now we are facing mutable-produce-immutable dispatching. Which will you choose?

💖 💪 🙅 🚩
frustigor
frustigor

Posted on September 9, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related