frustigor
Posted on September 9, 2020
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:
However, UX handler will push data back, so it comes to be a circle like this:
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:
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:
Yes, we get one way data flow, but we have to code here, here and here...
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:
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 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?
Posted on September 9, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.