Hi, Habr! I present to you the translation of the article "
Redesigning Redux " by Shawn McKay.
Should state management cause problems today? Intuitively, developers see the hidden truth: state management is much more complicated than it should be. In this article we will examine a few questions that you probably asked yourself:
- Do you really need a library to manage your condition?
- Did Redux deserve its popularity? Why or why not?
- Can we come up with a better solution? If so, which one?
Is a library needed for state management?
The front-end developer is not the one who simply moves the pixels from side to side; true art in knowing where to store state. It seems difficult only at first glance.
')
Let's take a look at the opportunities React gives us:

1. Component State
The state is stored inside the component. In React, we update
state
with
setState()
.
2. Relative State
The state passed from parent to descendant. In React, we pass
props
as a property of the child component.
3. Provided State
The state is stored in the provider (
provider ), and is available to any component (
consumer ), located below the tree.
Context API
in React.
View stores most of the state. But what about the rest of the code, which reflects the basic data and logic?
Placing all the code inside the components can lead to a low
division of responsibility : dependence on view libraries is growing, testing such code becomes more complicated, but the worst thing is that you have to regularly change the way the state is stored.
The structure of the application changes over time, and each time it is more difficult to determine which component needs a particular state. The easiest way is to remove all the state from the root component, which can be done in the following way.
4. External State (External State)
The state may be separate from the components that synchronously “connect” with it using the provider / consumer pattern. Most likely the most popular, among the libraries for managing the state, uses Redux. Over the past two years, it has gained great fame among developers. So what is the reason for such a love for one library?
Redux more productive? Not. In fact, the work of the application slows down a bit with each new action that needs to be processed.
Redux is easy to use? Of course not.
Native javascript would be simple:
So why can't everyone use
global.state = {}
?
Why redux?
Under the hood, Redux is similar to the global TJ object, only wrapped by a series of utilities.
In Redux, you can directly change state by
dispatching actions through the specified tools.
The library includes two types of action handlers:
middleware &
subscriptions . Middleware are functions that intercept actions. Include tools like “logger”, “devtools” or “syncWithServer”. Subscriptions are the functions used to send changes to components.
Finally, reducer (
reducer ) - these are functions that change the state and divide it into small, modular and manageable parts.
Most likely, Redux is more applicable for storing a state than a global object.
Think of Redux as a global object with advanced features and a simplified way to "transform" a state.
Is Redux so complicated?
Yes. There are several undeniable signs that the API needs to be improved; can be concluded using the following equation:
We believe that
time_saved means the time spent on developing your own solution, and
time_invested is equal to the hours spent reading the documentation, passing training courses and learning new concepts.
Redux is, in principle, a simple and small library with a steep learning curve. For every developer who has mastered and benefited from Redux, immersed in functional programming, there is another potential developer who is confused and thinks that “this is not for me, I’m going back to jQuery”.
You do not have to figure out what “comonad” is using jQuery, and you don’t have to understand the functional composition to cope with state management.
The goal of any library: to make complicated simple with the help of abstraction.
I do not intend to make fun of Dan Abramov. Redux has become popular at a too early stage of its development.
- How to make changes to the library, which is used by millions of developers?
- How do you justify the critical changes that will affect projects around the world?
You can not. But by providing extensive documentation, training videos, and community assistance, you will be invaluable. Dan Abramov did it.
Or maybe there is another way?
Improving Redux
Redux deserves a change, and I armed myself with six of its weak points to prove it.
1. Setup
I suggest looking at the
initial setup of the Redux application (left screen).
Many developers, immediately after the first step, stopped at a loss. What is
thunk ?
compose ? Is the function capable of this?
Redux is believed to be based on configuration over composition. The setting should look like the example on the right.
2. Simplify Reducers
Reduxers in Redux can use switch constructions far from those we used to use.
Considering that reductors are matched by the type of action, we can make each reducer a pure function that takes a state and an action. You can shorten the action and transmit only status and data.
3. Async / Await without Thunk
Thunk is widely used to create asynchronous actions in Redux. In many ways, thunk is more like a smart hack than a officially recommended solution. How it works:
- You pass the action as a function, not an object.
- Thunk checks every action that it is a function.
- If everything converges, thunk calls this function and passes some methods to it in it: dispatch and getState.
Seriously? Should we thus typify simple actions as an object, a function, or even a Promise?
Is it possible to use async / await, as in the example on the right?
4. Two kinds of actions
Think about it, because there really are two types of actions:
- Reducer action : starts the reducer and changes the state.
- Effect action : starts an asynchronous action. It may cause a reducer action, but the asynchronous function is not able to directly change the state.
The ability to distinguish the types of actions will bring more benefits than the use of "sleds".
5. No more variables storing the type of action.
Why is it customary to separate action generators (action creators) and reducers? Can one exist without the other? How to change one without changing the other?
Action generators and reducers are two sides of the same coin.
const ACTION_ONE = 'ACTIONE_ONE'
is an extra side effect of separating action generators and reducers. Treat them as a single whole and there will be no need for large files with export types.
6. Reducers are action generators.
Combine the elements of Redux for their intended purpose, and you get a simple template.
As a result, following this scenario, the
reducer can become an action generator .
Use the naming convention, and the following points will be fairly predictable:
- If the reducer is called “increment”, then the type will be “increment”. Even better, we denote as "count / increment".
- Each action transfers data through "payload".
Now, using
count.increment
we can create an action generator directly from the reducer.
Good news: we can improve redux
These problem pieces motivated the creation of
Rematch .
Rematch wraps Redux, giving developers a simplified API.
Here is the complete code example with Rematch:
I have used Rematch in production for the past few months. And what I think:
I have never spent so little time managing my condition.
Redux will not disappear and is not required. Master this library with a smaller learning curve, less boilerplate and less mental input.
Try a
rematch and find out if you like it or not.
Put a star to let others know about us.