In depth understanding of Redux (II)

Time:2021-8-5

Note 1: This article is mainly based on the personal summary record of “readme | Redux Chinese documents”. It is also a project for faster and better learning and accepting the operation of Redux and better application. Original document address:http://www.redux.org.cn/
Note 2: This article is long and may take some time to read and understand

This article mainly introduces three main concepts in Redux: action, reducer and state.

1. Action

Action is some objects defined in advance and represents the identifier that triggers an event. It must have a key forType field, the value type of type is a string. Usually, a separate file will be created to store all actiontypes. This file defines the value of type. It is as follows:

File name: actiontype.js

export const FIRST_ACTION = 'FIRST_ACTION'
export const MIDDLE_ACTION = 'MIDDLE_ACTION'
...

In addition to the required type field of action, we can also customize some other fields as needed. These fields carry the information passed into the store,It can be said to be the only source of data in the store.As follows:

const DEMO_ ACTION = 'DEMO_ Action '// a separate file is not created here to save actiontype

const action = {
    type: DEMO_ACTION,
    Payload: 'here is the data that can be passed into the store'
}

Store. Dispatch (action) // pass the action into the store through store. Dispatch

Note that we will not define an action for each state change separately. Usually, we will declare an action creation function

What is an action creation function? In fact, it is the method of generating action. In Redux, the action creation function simply returns an action:

function add() {
    return {
        type: 'ADD_WHAT',
        payload: {}
    }
}

The store can be accessed directly store.dispatch() Call the dispatch () method, but in most cases you will use the method provided by react reduxconnect()Helper to call.bindActionCreators() You can automatically bind multiple action creation functions to the dispatch () method. The bindactioncreators method will be introduced later.

2.Reducer

The action we just introduced is used to describe the occurrence of a specific event to trigger the change of state, so reducer is the rule that defines how to operate our state.

Reducer is a pure function. It accepts two parameters. The first is the old state and the second is the action object. After running, it returns a state.

    export function thisIsReducer(state={}, action) {
        switch(action.type) {
            case 'XXXX':
                //...
                return Object.assign({}, action.store)
                break
            case 'YYYY':
                //...
                return Object.assign({}, action.store)
                break
            default: 
                return state    
        }
    }

Note: we don’t want to modify the state, so we see that a new copy is created through object.assign. In addition, a state should be returned anyway.

  • Split reducer
    In daily development, an application will not have only one reducer. Usually, we will divide it into several small reducers. Each reducer manages a state item in the state tree, for example:
//Topic list reducer
export function themeListStore(state={}, actions) {
  switch (actions.type) {
    case ActionsType.THEME_LIST:
      state = Object.assign({}, state, actions.store);
      state.datas.map((item, index)=>{
        state.datas[index].isChecked = false;
        item.photoList.map((e, i)=>{
          item.photoList[i].isChecked = 0;
          item.photoList[i].rotateAngle = item.photoList[i].userRotate;
        })
      });
      return state;
    case ActionsType.THEME_SORT:
      if( actions.dir == 'up' && actions.curId == 0 ) {
        return state
      }else if( actions.dir == 'down' && actions.curId == state.datas.length-1 ){
        return state
      }else {
        if( actions.dir == 'up' ){
          state.starId = state.datas[actions.curId].themeId
          state.endId = state.datas[actions.curId-1].themeId
          return state
        }else if( actions.dir == 'down' ){
          state.starId = state.datas[actions.curId].themeId
          state.endId = state.datas[actions.curId+1].themeId
          return state
        }
      }
    default:
      return state
  }
}

//Switch photo batch movement and theme editing to add reducer
export function changeOptStore(state=0, actions) {
  switch (actions.type) {
    case ActionsType.CHANGE_OPT:
      if(actions.option == 0){
        state = 0
        return state
      }else if(actions.option == 1){
        state = 1
        return state
      }else if(actions.option == 2){
        state = 2
        return state
      }
      console.log(state, 'state')
    default:
      return state
  }
}

The above code is the reducer written just when using react reduce to manage data (please ignore some loose places).
Note that each reducer is only responsible for managing a part of the global state. The state parameters of each reducer are different, corresponding to the part of state data it manages.
The above is only the reducer in one file. Generally, better operations will be put into different files according to different pages to ensure its independence and be used to process different pages.

As we said before, there is only one store in the whole application. How can we integrate reducers scattered in different files?
Redux provides acombineReducers()Methods for integration.

import {combineReducers} from 'redux';
import * as commonReducers from './commonReducers';
import * as alertMsgReducer from './alertMsgReducer';
import * as uploadPhotoReducer from './uploadPhotoReducer';
import * as photoGraphyReducer from './photoGraphyReducer';

const rootReducer = combineReducers({
  ...commonReducers,
  ...alertMsgReducer,
  ...uploadPhotoReducer,
  ...photoGraphyReducer
});
export default rootReducer;

As mentioned above, we import all reducers in different files, and then import them throughcombineReducersIntegrate a root reduce person, and then export it. So what is after the integration? Let’s print it out and see:

In depth understanding of Redux (II)
As shown in the figure, the generated function is a function that calls a series of reducers. Each reducer swipes and processes part of the data in the state according to their key, and then the generated function combines the results of all reducers into a large object.

3.Store

Above, we learned that action defines the upcoming event in advance, and reducer defines the rules for processing data corresponding to the event. So store is the object that connects them:

  • Store is to save all States in the application,The store is single
  • Store. Getstate() can get state
  • Store. Dispatch (action) triggers action and changes state
  • Register listeners through subscribe (listener)
  • Log off the listener through the function returned by subscribe (listener)

How to create a store?

import {createStore} from 'redux'
import rootReducerfrom './rootReducer'

let store = createStore(rootReducer)

Createstore also has a second parameter, which is used to set the stateInitial stateIn this way, server-side rendering can be performed for homogeneous applications(original words of the document: This is very useful for developing homogeneous applications. The state structure of the server-side Redux application can be consistent with that of the client, so the client can directly use the server-side state received from the network for local data initialization.)

let store = createStore(todoApp, window.STATE_FROM_SERVER)
4. Data flow

Redux is a strict single data flow. There are four main steps in Redux from change to rendering to page:

  • In the view layer, dispatch an action through the event (action is an object that describes something happening)
  • Store calls the incoming reducer function. As mentioned earlier, the reducer will accept two parameters (the previous state and action objects)
  • The root reducer will merge and output multiple child reducers into a single state tree
  • The Redux store stores the complete state tree returned by the root reducer.
    This new tree is the next state of the application! All listeners subscribing to store. Subscribe (listener) will be called; The listener can call store. Getstate () to get the current state.

In depth understanding of Redux (II)
Looking at the above, we can find a better graph to show our data flow. I won’t repeat the explanation here. Compared with what I said before, I believe it can be seen clearly and clearly~

summary

Here is a brief summary: action is that we define some action objects as needed. We will trigger the reducer function of the queue through store. Dispatch (action). The reducer will change the state according to the rules, and finally the changed data will be presented in our view. Later, we will continue to introduce the use of react Redux in react and the operation of asynchronous action

Recommended Today

Java Engineer Interview Questions

The content covers: Java, mybatis, zookeeper, Dubbo, elasticsearch, memcached, redis, mysql, spring, spring boot, springcloud, rabbitmq, Kafka, Linux, etcMybatis interview questions1. What is mybatis?1. Mybatis is a semi ORM (object relational mapping) framework. It encapsulates JDBC internally. During development, you only need to pay attention to the SQL statement itself, and you don’t need to […]