As we all know, react can be abstracted as a function: UI = render(data). This means we can focus on building the data without thinking about how to update the view. However, as the complexity of single Page Application (SPA) increases, the state will become larger and the difficulty of managing the state will also increase. To better manage your application’s state, you might consider using the React state management library, but what should you consider and choose?

state

First we need to know what states are. For example, when we interact with our application, such as when we click on a button, a dialog box pops up, or the UI changes, or a request is sent. With the click event, our application responds accordingly. What is certain is that the state of the application is not the same as it was before the click. We have entered a new state of the application. Variables that indicate whether a popover is open or not, or data for an AJAX request, can be called states. Broadly speaking, the state of the application is these variables. It can be data stored in React using useState(function component) or this.state(class component), or it can be stored in a third-party state management library.

Front-end state management design — The art of elegance and compromise.

choice

If we need to store state in React, we usually use one of the following three ways:

  • Function components can use useState, useReducer hooks, and class components can be stored in this.state.

  • It is stored in the store of the third state management repository. Related libraries are: Redux, MobX, Recoil….

  • Maintain the state itself. For example, we can store the state directly in the window…

Correspondingly, if we change the state, we can:

  • When we call useState, useReducer, this.setState, React will automatically rerender. This is the mechanism provided by React.

  • If we use third-party libraries such as Redux, MobX, Recoil, etc… They will then call Ract’s API to trigger a re-render at the appropriate time.

  • If you maintain your own data, such as in Windows, you need to implement your own logic for state changes to trigger rerendering, but it is not recommended. Actually, React doesn’t really care where you put the data, it just deals with the data -> UI mapping.

In most cases, the component-level state management API provided by React is perfectly adequate.

Simple state sharing scenario

However, if we only use the React API, we often run into the following state sharing problems:

  1. The prop drilling problem is that the props are passed too deep. We need to pass the props manually.

  2. Two components on the far side of the tree need to share state. One way to do this in React is to extract props to their nearest ancestor node, returning to the first case.

  3. Child components pass data to parent components only by callback.

The root cause of these problems is React’s unidirectional data flow design, which is designed to keep all states at the top. Of course, there are pros and cons to a one-way data flow design. The pros are that each component’s dependencies (data flow) are clear, and the cons are that the state is shared. So React came up with the Context API. The Context API addresses dependency injection rather than state management itself. Blogged Answers Why React Context is Not a “State Management” Tool Jamiebuilds /unstated-next, the source code is very simple. If you look at the source code, you can see that there is a performance problem, and when you change the state, all the components that use the context will be rerendered. So they are only suitable for simple scenarios that require quick learning and low performance requirements.

Network intensive scenarios

This scenario is often seen in middle and background projects. Data needs to be frequently requested from the server, and the data after the request needs to be managed by loading state, cache and expiration. In this scenario, react-Query or SWR can be used. Take the React-Query feature:

  • The use of hooks API

  • Encapsulates the logic for many front-end asynchronous requests

  • Data cache control, automatic update data

  • Repeat request merge

  • Paging and lazy loading

  • .

Use React-Query to solve half your state management problems

A complex scenario

I think maybe the real complex scenarios are:

  • Users use it in complex ways

  • Different identities of users have different ways of using it (such as regular users and administrators)

  • Multiple users can collaborate

  • Interacting heavily with the server, or using WebSockets

  • A View retrieves data from multiple sources

  • .

In summary, complex state management libraries are needed in complex scenarios with multiple states, multiple interactions, multiple data sources, and data coupling. According to the design idea, they can be roughly divided into four categories:

  • Unidirectional data flow: Redux, Zustand

  • Reactive data flow /Proxy: Mobx, Valtio

  • Atomic: Recoil, Jotai

  • Stream: rxjs(Reactive Extension JavaScript)

Here it should be said that Redux, Mobx and so on are relatively low-level and framework-independent, they often have framework-associated libraries such as React-Redux, mobx-React.

conclusion

In the React ecology, there are many state management libraries, and we need to select one suitable for business scenarios according to our own needs. The following articles will introduce the main ideas and principles of several mainstream state management libraries used in React.