A common interview question is “What do you know about DATA flow management solutions?” First understand why you want to study data flow management, then review and compare what you know. Real front-end development, not only interview to build rockets, the actual work still need this ability.

What are the data flow management solutions?

Unidirectional data flow based on props

  • Parent -> Child component communication

Explanation of principle: This is the most common and best solution to a communication scenario. The React data flow is unidirectional. The parent component can pass this. Props to the child component to implement parent-child communication.

  • Child -> Parent component communication

Given that props is unidirectional, the child component cannot directly push its own data to the parent component, but the props can take a variety of forms. If the parent passes to the child a function that is bound to its own context, then when the child calls the function, it can give the data it wants to give to the parent in the form of the function’s input parameters, thus indirectly implementing the flow of data from the child to the parent.

  • Sibling communication

Sibling components share the same parent component, as shown in the figure below, which is a very important prerequisite.

In the above inter-component communication, direct sibling communication needs to be implemented by the parent component. The principle is also very simple, is the callback function plus the Props property. However, if it is not a direct sibling, one-way data flow based on callback functions and Props will increase the amount of code infinitely for cross-component communication, and state synchronization and state sharing will not be possible.

Use the Context API to maintain global state

Context API the React Context API provides a way for component tree global communication. Prior to React 16.3, the Context API was not officially advocated by React due to its limitations. React has improved the Context API since version 16.3. The new Context API is more usable.

The Context API has three key elements: React. CreateContext, Provider, and Consumer.

We can create a set of providers by calling React. CreateContext. Providers, as providers of data, can send data down to consumers at any level in their component tree.

Note that Cosumer can read not only the data delivered by the Provider, but also subsequent updates to the data. This means that data can be synchronized between producers and consumers in a timely manner, which is crucial for the Context schema.

Next, we show the specific usage in the code, highlighting the comments:

Context API solves the problems of Props to a certain extent, but when the business logic of a component is very complex, the code must be written more and more, and the problem of using Context API for data flow management will occur. The Context API does not separate the data layer from the presentation layer. It controls the data flow in the UI code inside the component. As a result, the entire component becomes bloated, the business logic is piled on top of each other and difficult to maintain, and the data flow becomes chaotic and difficult to manage.

When the data flow is chaotic, one of our execution actions may trigger a set of setStates. Therefore, how to make the whole data flow can be “monitored”, or even more detailed control of each step of data or state change, it is particularly important. We want the management of the data flow to be truly detached from the React component concept, completely removed from the UI layer to manage the data, and React to focus only on the View layer. So, we need to sort out the professional-level data flow management framework. As mentioned in the last post, there are a lot of great projects in the community.

Redux design principles

Flux

There was a point made at Facebook’s F8 conference in 2014 that MVC is more suitable for small applications. But when it comes to large front-end projects, MVC can make the project complex enough that the complexity of the system increases like crazy every time new functionality is added. As you can see in the figure below, the relationship between the Model and View is complex and difficult to understand and debug, especially with two-way data flow between the Model and View.

So they came up with an architecture based on one-way data flow. This structure idea, for data flow management, can be described as the following figure:

Let me first explain the concepts involved in the figure above.

View (View layer) : User interface. The user interface can be implemented in any form, the React component is one form, and Vue and Angular are all right. There is no coupling between the Flux architecture and React.

Action: Also known as a “message” sent by the view layer that triggers a change in application state.

Dispatcher: It is responsible for the distribution of actions.

Store (data layer) : It is the “repository” for storing application state, in addition to defining the logic for changing state. Store changes are eventually mapped to the View layer.

A typical Flux workflow looks like this: a user interacts with a View and initiates an Action through the View. The Dispatcher sends this Action to the Store to inform the Store of the appropriate status update. After the Store status update is complete, the View will be further notified to update the interface.

The most important thing about Flux is not Flux itself, but Flux’s design concept and scheme idea. This is a new breed that comes out of nowhere, with a new frame of mind, to the world of modern front-end development. However, in terms of application scenarios, Flux is currently rarely used in the industry except for large-scale applications within Facebook. Because the specific application code is still relatively complex, the most important thing about Flux is not Flux itself, but Redux, which evolved on the basis of Flux, is now the star style. It inherits all the design ideas and good ideas of Flux, while reducing the difficulty of specific coding (in fact, it is still more complex, but much simpler than Flux).

Redux

Redux is a JavaScript state container that provides predictable state management.

Redux is designed for JavaScript applications, which means it’s not exclusive to React. React works, Vue works, and native JavaScript works.

Redux is a state container, so let me give you an example of what a state container is. It’s like the water fountain in the office. All the employees are high and low. The water dispenser corresponds to Redux, which manages the data (water) and can be accessed by anyone (components) who needs it. In other words, data (water) and components (employees) are independent of each other. Using Redux to manage data, Store is the data maintained independently of components, which makes data management and components independent of each other and solves the problem of difficult data transfer between components.

To use Redux in React, install:

npm install redux react-redux
Copy the code

Redux consists of three parts: Store, Reducer, and Action. Let’s take a look at what each represents:

Store: Like the “water” in the water cooler, it is a single data source and is read-only.

I’m going to take action on this.

Reducer: is a function that distributes and processes changes and ultimately returns new data to the Store.

The close cooperation between Store, Action and Reducer forms a closed-loop workflow of Redux:

Throughout the work of Redux, the data flow is strictly one-way. This sentence is very important to remember.

For a React application, all the data states at the View level come from the Store. If you want to modify the data, there’s only one way to do it: Actions will be read by Reducer, and the data will be modified according to different action contents and a new state (state) will be generated. This new state will be updated into the store object, and corresponding changes will be driven at the view level.

For components, any component can read the global state from the Store by convention, and any component can modify the global state by reasonably distributing actions. Redux provides a unified state container, so that data can freely and orderly shuttle between any components, which is the idea of Redux to achieve communication between components.

Understand the Redux workflow from a coding perspective

At this point, you’ve learned about Redux’s design philosophy and element relationships. Next, we’ll explore Redux’s workflow from a coding perspective, visualizing the elements and processes mentioned above.

1. Use createStore to create the Store object.

The createStore method is where it all begins, receiving three input parameters: Reducer, initial state content, and specified middleware. In general, only the reducer is what you have to do. Let’s take a look at the reducer’s coding form.

2. The reducer returns the new state to the Store.

A Reducer must be a pure function, it can have various internal logic, but it must finally return a state. When we create a store based on a Reducer, we actually specify a set of update rules for the store:

3. Relied on dispatch, sent actions and informed reducer “Make changes happen”

In order for state to change, the correct action must be used to drive the change. Action objects allow multiple attributes to be passed in, but only Type is mandatory. Type is the unique identifier of the action. Reducer identifies different states that need to be updated through different types, so accurate “directional update” can be realized.

The action itself is only an object. To make the Reducer aware of the action, it needs to “dispatch action”, which is completed by store.dispatch.

The complete code structure is as follows:

Let’s look at the whole workflow according to the above code:

Here’s a quick example of adding and subtracting numbers:

I don’t know how you feel after reading this small case. I know you may find tedious code extremely distasteful. It’s like a long, smelly wrap around your feet. After using Redux for a while, many people have the biggest impression that Redux requires a lot of template code to write, and that it is better to just manage React. In fact, if you think about it carefully, it looks like Redux helps React manage the state. In fact, we transfer some of the React state to Redux. The difference is who is active and who is passive.

Note: Redux actually provides a set of tools. React just follows the instructions.

So it’s doomed that if you want to use Redux, you have to play by its rules, unless you don’t want to accept the model. There are pros and cons to this approach, but in a large, multi-person team, it is easy to form a protocol that makes the state flow clear. The downside is that for small, rapidly iterating teams, such heavy code templates can be a burden.

Next, let’s do a holistic analysis of Redux.

The advantages of the story

1) State persistence: GlobalStore ensures that a component retains its previous state even after it is destroyed.

2) State traceback: Each action will be serialized. Reducer will not modify the original state, but always return the new state, which is convenient for state traceback.

3) Functional Programming: Using pure functions, the output is completely dependent on the input, without any side effects.

4) Middleware: For asynchronous data flow, express-like middleware mode is provided. A large number of excellent third-party plug-ins have emerged in the community, which can control data flow more finely and play a buffer role in complex business scenarios.

The disadvantage of story

1) Heavy code templates: Modifying a state may involve four or five files, which may affect the whole process.

2) State residue in store: when multiple components share a state in store, pay attention to the initialization clearing problem.

3) Mindless publish and subscription: every dispatch an action will traverse all reducer and recalculate connect, which is undoubtedly a loss;

4) There will be lag when the interaction is frequent: if the Store is large and the store is frequently modified, the page will obviously see lag.

5) Typescript is not supported.

Redux vs. MobX

Let’s start with MobX. Taking Mobx 5 as an example, it actually uses ES6 proxy to track attributes (the old version was implemented with Object.defineProperty) by implicit subscription to automatically track monitored Object changes and update data.

While Redux does everything to the user to keep itself clean, MobX does the simplest things to the user and the rest to MobX in-house. Users don’t have to worry about this process, of course, but the basic idea remains that the Model and View are completely separate. We can write the business logic in the Action, and the user just needs to operate Observabledata.

Limited by space, the implementation of the specific code will not be expanded here. The Observerview responds automatically, which is MobX’s main focus on responsive design, but the programming style is still the traditional object-oriented OO paradigm. Vue uses data hijacking to implement two-way binding. React + Mobx is a complex Vue. One of the major changes in Vue3 is the transfer of proxy to proxy.

Now that we’ve talked about MobX’s advantages, here’s a quick summary:

1) Less code.

2) Accurate positioning based on data hijacking (local update in a real sense).

3) Multi-store business logic (Model View separation).

4) Good responsive performance (frequent interactions are still acceptable).

5) It can completely replace React state management.

6) support Typescript.

In fact, the mainstream data flow management is divided into two main schools: one is the functional library led by Redux, and the other is the reactive library led by MobX.

The code involved in this article has been open source, welcome to visit the exchange.