React and Redux are growing rapidly in the front-end industry. React has 42000 + star on Github, which is higher than jquery’s 39,000 + star, and will soon surpass Angular 1’s 49,000 + star. Redux’s star count is close to 20,000, which shows the level of enthusiasm for redux. What’s the magic that’s driving people crazy? Let’s get in the car and try it out for ourselves. This article is biased towards explaining the Redux process.

Based on the react + Redux model development, we specified a set of parallel development process with clear division of labor. Here’s a look at the entire app development process using an example of an “Apple basket.”

First, let’s look at the prototype of this example:

You can do two things — pick apples and eat apples. When you pick an apple, the app sends an Ajax request to the background for an apple, each of which has two properties: number and weight. When you eat an apple, you don’t have to tell the background, just eat it in front of you. The apple basket shows the current number of apples and the number of apples that have been eaten. Good! So let’s get to work!

Here’s an overview of the fundamentals of Redux:

The logic of the whole Redux process is very clear. The data flow is one-way, like a production line:

Store -> Container -> Reducer -> Store

This is good for fine division of labor and collaboration.

Let’s look at these three concepts:

  • Store is the state management center of the application, storing the state of the application. When receiving the update of the state, the visual component will be triggered to update.

  • A Container is a container for visual components. It renders the incoming state variables into visual components and displays them in the browser.

  • Reducer is the action processing center, which processes actions and generates new states that are returned to the Store.

NOTE: Reducer is part of the store in terms of the object containment relationship, but logically we split it so that we can understand the whole Redux process more easily.

We can make an image metaphor, js as a bus, store, container and Reducer as three stations, and state and Action as two kinds of passengers. This is a loop bus:

  1. The JS bus departs from the Store station and picks up state passengers, who get off at a container station and put themselves on display

  2. After a while, an Action passenger got on the bus and js bus sent the Action passenger to reducer station, where the Action passenger and state passenger had a child new State. Js bus takes New State back to store station

Redux only defines the data flow of the application. It only solves the problem of the “model layer”. It also uses React, Angular, etc., as the “UI layer”.

Before we get started, here are some references to React and Redux. If you don’t understand react and Redux, check out the references below:

The js code shown below uses a small amount of simple ES6 syntax. You can refer to it when you encounter it, or you can look it up yourself:

  • Import/export: ES6 code modularization mode

  • Let declaration statement: block-level variable declaration statement

  • Arrow function: (..) = > {.. Function of the form}

We will use the Babel compiler to compile ES6 syntax into ES5, so you don’t have to worry about browser compatibility and feel free to use ES6.

The basic configuration of the application is the responsibility of the front-end development lead, so you don’t have to understand it in detail.

Explain step by step according to the division of tasks

According to the content of development, we divided the front-end team into two groups: “layout group” and “Logic group”, each group had two tasks, a total of four tasks.

  • Layout group – Responsible for contianer, Component

    • Task 1: Static Layout – Use HTML + CSS static layout

    • Task 2: Dynamic Layout – Dynamically render a static layout using JSX syntax

  • Logical group – Responsible for action and Reducer parts

    • Task 1: Action development – Make the action for the Redux process

    • Task 2: Reducer development – Make the reducer of the REdux process

The layout group is required to be familiar with HTML + CSS layout, only simple JS is required, no complete understanding of the Redux process is required. The logical group is expected to be familiar with JS, preferably with a complete understanding of the Redux process, but not with HTML + CSS layout.

Next, I’ll show you the SRC directory for our tutorial. Here you can scan first, just to get a general idea

-src source folder: contains the project's source code, which is where we do most of our development. Store common display components, such as "Apple" -Actions actions folder: Store the action-reducers reducers that can be issued folder: Store the action-processor reducers-Services service folder: -styles folder: stores application styles, such as CSS and SCSS-images. Image folder: Stores image resources. -apis Development interface folder: Stores development interface documentsCopy the code

Let’s start with the layout group.

The layout of the group

Task 1: Static layout

  • Ability: only need to be able to use HTML + CSS (SASS) layout

  • Task content: 1. Apple basket component (container component) 2. Fruit component (display component)

Redux’s components are divided into two categories: container component and common display component. The container is responsible for receiving the state in the Store and sending the action. Most of the time, the container needs to be directly connected to the store. Ordinary components are placed inside a container, which determines when, how much, and what to display, and are typically used multiple times.

1. AppleBasket container AppleBasket. JSX + AppleBasket

The prototype of the Apple Basket component is as follows:

For containers, we write them as React component classes, which are mostly static JSX code, equivalent to HTML.

Below is the AppleBasket JSX

import React from 'react';
import { connect } from 'react-redux';

class AppleBusket extends React.Component {
  
  render(){
    return (
      
       
Apple basket
The current
0 apples, 0 grams
Have eaten
Two apples, 480 grams
The apple basket was empty
Pick apples
); } } export default connect()(AppleBusket);Copy the code

The static layout developer is also responsible for the writing style, which is written using sass. The following example is appleBasket. SCSS.

.appleBusket{ width: 400px; margin: 20px; border-radius: 4px; border: 1px solid #ddd; >.title{ padding: 6px 0px; text-align: center; color: #069; font-size: 20px; //font-weight: 600; } >.stats{ width: 100%; $border: 1px dashed #ddd; border-top: $border; border-bottom: $border; padding: 10px 0px; .section{ display: inline-block; width: 50%; padding-left: 8px; .head{ padding: 6px 0px; font-size: 16px; color: #069; } .content{ font-size: 20px; font-weight: 200; } &:first-of-type{ border-right: 1px solid #f0f0f0; } } } >.appleList{ padding: 10px 0px; .empty-tip{ text-align: center; font-size: 16px; color: #ccc; padding: 20px 0px; } } >.btn-div{ text-align: center; button{ color: #fff; background-color: #096; border: none; font-size: 14px; padding: 6px 40px; border-radius: 6px; margin: 20px auto; }}}Copy the code

2. Apple component AppleItem.jsx + Appleitem.scss

The Apple component looks like this:

A normal component is defined in a similar way to a container, except that it does not need to be wrapped with a Redux connector, as follows:

AppleItem.jsx

import React from 'react';

class AppleItem extends React.Component {

    render() {

        return (
            
       
Red Apple one
265 g
eat
); } } export default AppleItem;Copy the code

The style file appleItem.scss is omitted here.

It is not 100% clear which display elements should be used as containers and which should be used as ordinary components, but you can classify them according to your own understanding.

This is the content of task 1, writing a static layout, which is basically HTML + CSS, and does not involve JS code.

Task 2: Dynamic rendering

After writing the static layout, it’s time to render it dynamically

Dynamic rendering sounds fancy, but it simply means displaying content based on a Stete data object. The first step is to determine the structure of its state. The state of the container is a part of the state in the store. The front-end administrator will agree its data structure in advance and present it in the corresponding Reducer. Just go there and copy it. The state of a normal component can be defined by itself and specified in a file.

1. Dynamic rendering of containers

If you go to applebasketreducer.js, you can get the state structure of the fruit basket as follows:

{
    isPicking : false,
    newAppleId: 1,
    apples: [
        /*{
            id: 0,
            weight: 235,
            isEaten: false
         }*/
    ]
}Copy the code

Our data structure “instantiates” it in AppleBasket. JSX as follows, and we start writing our dynamic rendering code as follows:

import React from 'react'; import { connect } from 'react-redux'; import AppleItem from '.. /components/AppleItem'; class AppleBusket extends React.Component { render() { let { state } = this.props; // Let mockState = {isPicking: false, newAppleId: 3, apples: [{id: 1, weight: 235, isEaten: true }, { id: 2, weight: 256, isEaten: false } ] }; State = mockState; // Set state to display level let stats = {appleNow: {quantity: 0, weight: 0}, appleEaten: {quantity: 0, weight: 0}}; state.apples.map(apple => { let selector = apple.isEaten ? 'appleEaten':'appleNow'; stats[selector].quantity ++; stats[selector].weight += apple.weight; }) return (
       
Apple basket
The current
{stats.applenow. quantity} apples, {stats.applenow. weight} grams
Have eaten
{stats. AppleEaten. Quantity} an apple, {stats. AppleEaten. Weight}
{ state.apples.map(apple => ) }
Pick apples
); } } function select(state) { return { state: state.appleBusket } } export default connect(select)(AppleBusket);Copy the code

As you can see, dynamic layout requires only HTML + CSS layout on the basis of JSX syntax ability.

2. Dynamic rendering of common display components

Dynamic rendering of a normal display component is similar to that of a container, except that state can be specified and a mockState is given for the sample, which can be used by the user of the component passing in data from the sample.

The appleitem.jsx update is as follows:

import React from 'react'; class AppleItem extends React.Component { shouldComponentUpdate(nextProps) { return nextProps.state ! = this.props.state; } render() { let { state, actions } = this.props; */ let mockState = {id: 1, weight: 256, isEaten: false}; / let mockState = {id: 1, weight: 256, isEaten: false}; let mockActions = { eatApple : id => console.log('eatApple',id) }; /** * Switches this line of code to switch the data source loaded. * Open during development, use internal state and action, comment off after development */ state = mockState; actions = mockActions; if (state.isEaten) return null; return (
       
Red apple - {state.id} number
{state. Weight}
Actions. EatApple (state. Id)} >
); } } export default AppleItem; Copy the code

Container vs. plain display component state:

  1. The state of the container is obtained directly from the total state in the store. Note that applebusket.jsx follows this code:

    function select(state) {
        return {
            state: state.appleBusket
        }
    }Copy the code

    Select is a state filter that selects appleBusket from the total state as the state of the container. The format of this state will be specified in the reducer (because we need to provide the default value of the corresponding state in the reducer).

  2. The state format for a normal display component is agreed upon by the component developer, with examples in the mockState section. When someone wants to use your display component, you must pass in state data in the format you specify. In the component, we usually implement an auto-switcher like the following. When the user of the component does not pass in state when using the component, the internal simulated state will be displayed for the user to preview the effect.

    if(state === undefined)  state = mockState;Copy the code

This is the layout group development work: static layout + dynamic layout. The former requires only HTML + CSS layout, while the latter requires some JSX syntax and basic JS syntax.

Logical group

Task 1:The action to develop 

Task content: Develop the actions for the Redux process and deploy them into the corresponding containers and components. Skills required: Familiarity with JS and ability to use JQ ajax functionality is required.

First, let’s look at the definition of action.

1. Action in the narrow sense

Action in the narrow sense refers to a simple object, the structure of the object is as follows, as long as the object contains the type attribute to indicate the name of the action, at the same time, in other attributes of the object, you can save other relevant data in any form.

let action = {
    type: 'ACTION_NAME',
    ...
}Copy the code

Generally, the content of type is in the uppercase letter + underscore format.

Based on this definition, the industry proposes a Standard action called Flux Standard Action. In addition to the type attribute, an action can only add (but not necessarily contain) the three attributes: payload, error, and meta.

Let FSA = {type: 'ACTION_NAME', payload:, // Action payload: // Specifies whether the action is an error-loaded action meta: // Action metadata contains information explaining the meaning of the action}Copy the code

Here is the apple Action:

Let FSA = {type: 'EAT_APPLE', payload: 3, payload: 3, '// (not required)}Copy the code

An action is just an object that needs to be called by the store’s dispatch function depending on its timing to start processing: store.dispatch(action_1).

2. Action in a broad sense

In a broad sense, action refers to the data types that can be called by the Dispatch function with the support of middleware. In addition to ordinary action, common actions include Thunk, Promise, etc. Let’s use the common thunk for an example.

A thunk is simply a snippet of code that can be interpreted as a specific function, and we can dispatch the thunk. The thunk function has the following signature

(dispatch, getState) => {// In the function body we can use the dispatch method to send other actions // in the function body we can use the getState method to get the current state}Copy the code

Here’s an example of our apple-picking action:

let pickAppleAction = (dispatch, getState) => { ajax({ url: '/pickApple', method: 'GET',}). Done (data => {// Send normal action dispatch({type: 'DONE_PICK_APPLE', payload: data. data.weight} }); }). Fail (XHR => {// send an error dispatch({type: 'FAIL_PICK_APPLE', payload: new Error(xhr.responseText) , error: true }); })}Copy the code

Once defined, we can call thunk directly like this:

dispatch( pickAppleAction )Copy the code

Next, let’s make a further optimization and unify the action into actionCreator. It’s not hard to notice that {type: ‘ACTION_NAME’… } is cumbersome and error-prone. ActionCreator is designed to solve this problem. ActionCreator is a function that generates specific actions (in this case, generalized actions).

Var eatApple = function(id) {return {type: 'EAT_APPLE', payload: Id => ({type: 'EAT_APPLE', payload: id})Copy the code

On the one hand, it is easy to use and on the other hand, it is documentation. Just launch the action like this:

dispatch(eatApple(3))Copy the code

The Action Creator wrapper for normal actions can be done automatically using Redux-Actions, and you can quickly get started by looking at its documentation and using it as needed.

In the project, we will write an action file for each block and use actionCreator uniformly, so the final appleAction.js looks like this:

import ajax from '.. /services/ajax'; Const prefix = 'apple/'; const prefix = 'apple/'; Let actions = {// Note that () =>... PickAppleAction is not an actionCreator, but a Thunk pickApple: () => (dispatch, getState) => {// End thunk if(getState().ispicking) return; BeginPickApple ()); // Send a pickApple request ajax({url: '/appleBasket/pickApple', method: 'GET' }).done(data => { dispatch(actions.donePickApple(data.weight)) }) .fail(xhr => { dispatch(actions.failPickApple(xhr.responseText)); }) }, beginPickApple: () => ({ type: 'apple/BEGIN_PICK_APPLE' }), donePickApple: appleWeight => ({ type: 'apple/DONE_PICK_APPLE', payload: appleWeight }), failPickApple: errMsg => ({ type: 'apple/FAIL_PICK_APPLE', payload: new Error(errMsg), error: true }), eatApple: appleId => ({ type: 'apple/EAT_APPLE', payload: appleId }) }; export default actions;Copy the code

This way, by introducing AppleAction.js, you can quickly use defined actions, combined with the smart prompt function of some editors, which is very convenient. Here’s what vsCode editor looks like:

Once you’ve written the action, you just need to install the action in the corresponding position of the Container. Here is the overall code for applebasket.jsx:

import React from 'react';
import { connect } from 'react-redux';

import AppleItem from '../components/AppleItem';
import actions from '../actions/appleActions';

class AppleBusket extends React.Component {
    render() {
        let { state, dispatch } = this.props;
        ...
        return (
          ...
          
       
{ state.apples.map(apple => dispatch(actions.eatApple(id))}} key={apple.id} /> ) }
Dispatch (actions. PickApple ())} > pick apples
... ) } } function selectState(state) { return { state: state.appleBusket } } export default connect(selectState)(AppleBusket); Copy the code

Notice these two lines. This is where the action is loaded

Actions ={{eatApple: id => dispatch(actions.eatapple (id))}} dispatch(actions.pickapple ())}> pickAppleCopy the code

The Actions introduced in the code above is actually actionCreators.

In addition, actionCreator can be used very succinctly: The Dispatch level encapsulation of actionCreator can be done automatically using the bindActionCreators function provided by Redux. You can then call the Action directly instead of using the Dispatch method to call actionCreator. Look at the updated code below:

import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

import AppleItem from '../components/AppleItem';
import actions from '../actions/appleActions';

class AppleBusket extends React.Component {
    render() {
        let { state, actions} = this.props;
        ...
        return (
          ...
          
       
{ state.apples.map(apple => ) }
Pick apples
... ) } } function selectState(state) { return { state: state.appleBusket } } function buildActionDispatcher(dispatch) { return { actions: bindActionCreators(actions, dispatch) } } export default connect(selectState, buildActionDispatcher)(AppleBusket); Copy the code

Note these three changes:

let { state, actions } = this.props; Actions ={{eatApple: actions.eatapple}} Pick applesCopy the code

Let’s compare this to the previous way:

let { state, dispatch } = this.props actions={{eatApple: Id => dispatch(actions.eatapple (id))}} dispatch(actions.pickapple ())}> pickAppleCopy the code

You can see how much cleaner the code is with the new approach!

However, this approach prevents the editor from parsing object properties:

At this point, you need to look at the definition of the actions object in the actions file and fill in the action at the target location, but this is not too much trouble. And for developers using editors with no object property hints, this drawback simply doesn’t exist. We recommend, but don’t require, the dispatch wrapped action to be used on your own.

For normal display components

For general display component actions, we use the actions property as follows:

AppleBasket.jsx

. .Copy the code

AppleItem.jsx

. Actions. EatApple (state. Id)} > eat...Copy the code

The common display component accepts parent actions using the uniform Actions property. You can create a mockActions within the component, which has both document and test functionality. This is very useful:

Let mockActions = {eatApple: id => console.log('eatApple',id), // specify the function's signature foo: (arg1,arg2) => console.log('foo',arg1,arg2) // Also responds to call test}; /** * Toggle this line of code to switch loaded state and actions sources. * Open during development, use internal state and action, comment off after development */ state = mockState; actions = mockActions;Copy the code

Click on the “pick apple” and “eat” buttons, and look at the console. It’s ready to issue the action we want:

Ok, so that’s it for actions development. Let’s summarize our encapsulation of actions:

action -> actionCreator -> actionDispatcher

Task 2: Reducer development

Reducer is the action processor. The development is unambiguous: develop a class of functions that take action and the current state and return the new state.

Technical requirements: Familiar with JS, using the immutable data static library is required.

Below is a diagram of the Reducer function:

Let’s first look at the data structure of our Apple block state, very simple, here is the state at a moment:

{
    isPicking : false,
    newAppleId: 1,
    apples: [
        {
            id: 0,
            weight: 235,
            isEaten: false
        }
    ]
}Copy the code

There are three first-level attributes:

  • IsPicking: indicates whether an apple is being picked. As we know from above, picking an apple is actually sending an Ajax request to the background to pick an apple. During the request, we will set isPicking to true, indicating that the apple is being picked

  • NewAppleId: indicates the id of the new apple

  • Apples: An array of apples that holds apple objects, the structure of which is instantiated in the apples array.

We mentioned above that actions can be defined broadly as actions and narrowly as ordinary actions. In fact, non-ordinary actions, such as thunk, will usually end up launching ordinary actions. We only need to deal with ordinary actions in a narrow sense. In our Apple-picking app, there are four general actions:

BeginPickApple: () => ({type: 'apple/BEGIN_PICK_APPLE'}), // donePickApple: FailPickApple: error => ({type: 'apple/DONE_PICK_APPLE', payload: appleWeight}), // Fail to pick apples failPickApple: error => ({type: 'apple/FAIL_PICK_APPLE', payload: error, error: true}), // eatApple: appleId => ({type: 'apple/EAT_APPLE', payload: appleId })Copy the code

The following is the basic structure of reducer according to actions:

(state = defaultState, action) => { switch (action.type) { case 'apple/BEGIN_PICK_APPLE': //TODO return state; case 'apple/DONE_PICK_APPLE': //TODO return state; case 'apple/FAIL_PICK_APPLE': //TODO return state; case 'apple/EAT_APPLE': //TODO return state; default: return state; }};Copy the code

Reducer is a reducer function that accepts state and action. Inside the reducer function, actions are determined according to action.type and state (either new or original) is returned for each action.

We take the apple/EAT_APPLE action as an example to explain how to write reducer. The EAT_APPLE action is simply to eat an apple, and we can do this simply by setting the isEaten property of the apple object to true.

In general thinking, we would deal with it like this:

. case 'apple/EAT_APPLE': state.apples[action.payload].isEaten = true; return state; .Copy the code

However, this method does not work in redux because it does not cause the Store to trigger react for rerendering. Why? Because newState == oldState! Here are some explanations:

First, to start from the js object equality judgment operation, we look at the following code

let a = { foo: 'bar'}; let b = { foo: 'bar'}; console.log( a == b ); // The result is falseCopy the code

A and B look the same, but why false? Because object and array assignments are referential assignments, a and b are just referential symbols that refer to different object entities (e.g. A -> object#001, b -> object#002), Js object (array) equality is determined by whether to refer to the same object entity (object#001? = object#002 // false), see MDN.

Consider the following example:

let a = {foo: 'bar'}; let b = a; b.foo = 'good'; console.log( a == b ); // The result is trueCopy the code

NewState == oldState

Redux decides whether to notify React updates based on whether the returned state has changed. In light of this situation, someone might have improved the reducer just now:

    state.apples[action.payload].isEaten = true;
    newState = Object.assign({},state);
    return newState;Copy the code

So, click the “eat” button, and there it is, the apple is gone! However, this writing method only meets the trigger conditions of REDUx updating visual components, and has great limitations. It is not the reducer stipulated by reDUx. Let’s look at the correct reducer:

First, the reducer has such important constraints: in the Reducer, the original state cannot be modified, and the state of each version needs to be kept unchanged.

This kind of Persistent data structure is very common in Functional programming. In our Redux application, the meaning is:

1. Significance of debugging: Keeping the invariance of state in each version enables us to track state at each moment and track the “development history” of the application. This feature brings great convenience to debugging.

2. Performance implications: The constraint of keeping state constant leads us to use a method of locally updating objects, which can be very effective in improving the rendering efficiency of React or other display frameworks. Let’s take a look at how to update state in order to keep data invariant. Take our Apple basket state as an example:

Example: notice to start picking apples: apple/BEGIN_PICK_APPLE

To ensure state invariance for each version, we have two implementations: “deep copy” and “shallow copy”. Let’s look at the internals of the two modes:

Deep copy: One might think: “It’s easy to keep the state immutable. Just copy a state deep and let the new state change as you like.” The following is the deep copy

This is a very low level way of maintaining invariance:

  1. The deep replication operation is inefficient

  2. There is no setup to improve rendering efficiency in the rendering process

It simply caters to the constraints of maintaining data invariance, although it has certain debugging significance, but it does not improve the performance of the program, but reduces the overall performance of the program! No practical significance.

Shallow replication: In shallow replication mode, only the reference whose internal data has changed is updated

The internal data of the “state” object changes, so a new state reference is created; The internal data of the Apples Array does not change, so this reference is not updated! In this operation, this shallow copy method is relatively efficient, and it simply implements data invariance, which brings convenience for debugging, but also, more importantly, this shallow copy method greatly improves the efficiency of the visual component rendering stage! Let’s compare: When the user clicks to pick the apple, the renderer needs to re-traverse the entire tree of State objects to make visual updates with “deep copy”, whereas with shallow copy to achieve data immutability, the renderer only needs to traverse the level 1 child nodes of the State object instead of traversing the Apples array, greatly improving performance. Especially when there are a lot of apples, the performance gap between the two methods is very obvious.

Note: In the React component, shouldComponentUpdate should be enabled to increase the performance of the react component, like this:

. shouldComponentUpdate(nextProps) { return nextProps.state ! = this.props.state; }...Copy the code

Below we give a reducer shallow replication example:

Now that you understand how data immutability works with shallow replication, let’s look at the code implementation.

Our code is written in ES6, which uses two very convenient features of ES6:

  1. Obejct.assign() method, which is used to generate a new object

  2. Spread operator:…

Take a quick look at the documentation, or look at my example below to see how it works:

// apple basket reducer export default (state = { isPicking: false, newAppleId: 1, apples: [ { id: 0, weight: 235, isEaten: false } ] }, action) => { let newState ; switch (action.type) { case 'apple/BEGIN_PICK_APPLE': newState = Object.assign({}, state, { isPicking: true }); return newState; case 'apple/DONE_PICK_APPLE': newState = Object.assign({}, state, { apples: [ ...state.apples, { id: state.newAppleId, weight: action.payload, isEaten: false } ], newAppleId: state.newAppleId + 1, isPicking: false }) return newState; Case 'apple/FAIL_PICK_APPLE': // newState = object. assign({}, state, {isPicking: false}); return newState; case 'apple/EAT_APPLE': newState = Object.assign({}, state, { apples: [ ...state.apples.slice(0, action.payload), Object.assign({}, state.apples[action.payload], { isEaten: true }), ...state.apples.slice(action.payload + 1) ] }) return newState; default: return state; }};Copy the code

Immutable.js is a library for immutable data (also produced by Facebook). It can be used to generate immutable data by using a similar method to assignment. Here’s how it makes development easier:

We use the reducer apple/EAT_APPLE to illustrate.

Here is the original Reducer:

. case 'apple/EAT_APPLE': newState = Object.assign({}, state, { apples: [ ...state.apples.slice(0, action.payload), Object.assign({}, state.apples[action.payload], { isEaten: true }), ...state.apples.slice(action.payload + 1) ] }) return newState; .Copy the code

This is a reducer using the immutable.js library:

import { fromJS } from 'immutable'; . case 'apple/EAT_APPLE': return fromJS(state).setIn(['apples',action.payload,'isEaten'], true).toJS(); .Copy the code

With immutable. Js, you can do it in one line of code! If the team had agreed that state should be immutable, it would have saved fromJS and toJS conversions.

This concludes the reducer task presentation

conclusion

Now that the four tasks have been introduced and you should have some idea of the Redux process, let’s review our four tasks:

In this way, the main processes of React + Redux have been defined by routing. This model has high constructability, allowing very complex single-page applications to be built without increasing the development complexity due to the increasing business complexity of the application.

And within this division of labor, layout pairs focus on writing style layouts, mostly basic HTML+CSS work; Logic group focuses on the development of application logic, basically JS work, the division of labor is very clear planning, people can better do their own responsible work, the coupling of each component is very low, personnel arrangement flexibility is relatively large.

React + Redux redux redux redux redux redux

Some dependent JS libraries are not introduced here, you can check out the related JS libraries later.

The resources

  1. MDN Javascript Documents

  2. Introduction to ECMAScript 6 by Yifeng Nguyen

  3. IVAN ROGIC “React, Redux and Immutable. Js: Ingredients for Efficient Web Applications”

List of project-related JS libraries:

  • Webpack: JS development environment and packer

  • Babel: ES6 compiler

  • React: The current hot display framework

  • React – Router: a front-end router that works with react

  • Redux: State container for Web applications (defines a very clear data flow)

  • React-redux: the react and Redux connector

  • Redux-logger: Redux’s console log middleware

  • Redux-thunk: Thunk middleware for Redux

  • React-router-redux: indicates the react-router and redux connector

  • Immutable. Js: JS persistence data framework

  • Mock. js: a framework for generating mock background data

  • Jquery: In this project, we only use its very common Ajax functionality

Thank you for reading. I hope this article is helpful. Welcome to comment and discuss.