Recently, I have been reading Xiu Yan’s “React in A Simple Way”. My writing style is very interesting, and there is no lack of useful things. After reread several times, I still get a lot of things. There are about 15 articles in this series. If you think it is helpful, you can give a star. If you find any problems, please feel free to correct them in the comments section.

The data flow

React’s core feature is data-driven views, which are well known in the industry as a function:

UI = render(data)
UI = f(data)
Copy the code

The React view changes as the data changes. When we talk about component communication, we actually establish data connections between components. This is a set of interlocking React data flow solutions.

Unidirectional data flow based on props

Simple communication between parent, child, parent, and sibling components can be realized based on props parameter transmission. One-way data flow refers to that when the state of the current component flows in the form of props, it can only flow to components at a lower level in the component tree than itself. One-way data flow scenarios in React include,

  • Parent-child communication based on props: The state of the parent component is the props of the child component
  • Parent communication based on props: The parent component passes a function bound to its own context
  • Communication between siblings based on props: the parent component is unbridged and converted to parent + parent communication

The above three scenarios are suitable for the props parameters. If the communication requirements are complex, the one-way data flow based on props may not be suitable. We need to consider other flexible solutions, such as the publish-subscribe mode, which is a cure-all for communication problems.

Use a publish-subscribe model to drive data flow

The advantage of publish-subscribe mode is that as long as components are in the same context, the locations of monitoring events and triggering events are not limited. Therefore, in principle, we can realize the communication of any component based on publish-subscribe mode.

class EventEmitter {
  constructor() {
    this.eventMap = {};
  }

  on(type, handler) {
    if(! (handlerinstanceof Function)) {
      throw new Error('event handler expect to be a function');
    }
    if (!this.eventMap[type]) {
      this.eventMap[type] = [];
    }
    this.eventMap[type].push(handler);
  }

  emit(type, params) {
    if (this.eventMap[type]) {
      this.eventMap[type].forEach((handler, index) = >{ handler(params); }); }}off(type, handler) {
    if (this.eventMap[type]) {
      this.eventMap[type].splice(this.eventMap[type].indexOf(handler) >>> 0.1); }}}Copy the code

In addition to the two methods described above, we can also use the React native Context API for global communication.

Use the Context API to maintain global state

Context API the React Context API provides a way for component tree global communication.

Context is based on the producer-consumer pattern. React has three key elements: React. CreateContext, Provider, and Consumer. You can create a set of providers by calling React. CreateContext. As the Provider of data, the Provider can send the data to consumers at any level in its component tree. Cosumer can not only read the data sent by the Provider, but also read the subsequent updates of the data.

const AppContext = React.createContext();
const [Provider, Consumer] = AppContext;

<Provider value={ content: this.state.content} >
  <Content />
</Provider>

<Consumer>
  {value => <div>{value.content}</div>}
</Consumer>
Copy the code

Here is a simple diagram of the Context workflow,

Before V16.3, Context was not officially recommended for use by React due to various limitations. What are the limitations of the old Context?

  • Code not elegant enough: The producer needs to define childContextTypes and getChildContext. The consumer needs to define contextTypes to access the data provided by the producer through this.context. It can be difficult to tell who is a Provider and who is a Consumer

  • Data may not be synchronized in a timely manner: If a Context provided by a component changes and the parent component’s shouldComponentUpdate returns false, the descendant component that uses this value will not be updated. This violates the schema’s definition that Cosumer can read not only the data delivered by the Provider, but also subsequent updates to the data, resulting in data that may not be synchronized between producers and consumers.

Since V16.3, the new Context API has improved this. Even if the component’s shouldComponentUpdate returns false, it can still propagate through the component to descendant components, plus more elegant semantic declarative writing. Context becomes a viable communication solution for the React component.

Now that you understand the Context API, let’s continue with the React component communication solution in tandem.

The “class representative” of the tripartite data flow framework: Redux

Simple cross-level component communication can be done by using the publish/subscribe mode or Context API. As the complexity of the application increases, more and more states need to be maintained, and the relationship between components becomes more and more complex, we can consider introducing a three-party data flow framework, such as 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. It works with any framework or native Javascript. We know that state is actually data, the so-called state container, is a repository of public data.

To understand predictable state management, we need to know what Redux is and what its workflow looks like.

Redux consists of three parts: Store, Reducer, and Action.

  • A store is a read-only single data source
  • Action is an object that describes state changes
  • Reducer is a pure function that distributes and processes changes

Throughout Redux’s work, the data flow is strictly one-way,

To understand the Redux workflow from a coding perspective,

Create a Store object using createStore

import { createStore } from 'redux';
const store = createStore(reducer, initialState, applyMiddleware());
Copy the code

CreateStore accepts three incoming parameters: Reducer, initial state, and middleware.

The job of the Reducer is to return the new state to the Store

Reducer is a pure function that accepts the old state and changes and returns a new state without any side effects.

const reducer = (state, action) = > newState
Copy the code

When we created a store based on reducer, we actually specified a set of update rules for the store.

Action notifyreducer “Make changes happen”

Action is an object that contains its own unique identifier. In order to hit a desired state in the vast store state library, the correct action must be used to drive it.

const action = { type: 'ACTION_TYPE'.payload: {}}Copy the code

Dispatch is used to dispatch actions

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

store.dispatch(action)
Copy the code

After the action is dispatched, the reducer responds to trigger the state update in the store

Related articles

  • React Advanced: The Life Cycle
  • React Advanced series: Hooks Design Motivations

Write in the last

This article first in my blog, uneducated, unavoidably have mistakes, the article is wrong also hope not hesitate to correct!

If you have questions or find mistakes, you can ask questions and errata in the comments section,

If you like or are inspired by it, welcome star and encourage the author.

(after)