Water can put the stone through, ten thousand efforts to natural – zZ Sen

Figure out how Redux works

preface

As we all know, both React-Redux and VUEX are public state management mechanisms that reference Redux. If you understand how Redux works, you will understand a management mode for the common state of the two large view frameworks. Next, let’s explore how it works.

Summarize the operation principle of Redux

Confused by the first picture? First, to my understanding, I want to summarize how Redux works as shown in the figure above.

  • Create a repository: Create a repository for storing and managing common state.

It’s not hard to understand, to manage the public state, the first thing is to find a place for it to store, I call it a warehouse. There are two places in the repository for state and events that change the state, called the state pool and the event pool, and the repository provides methods for manipulating states and events.

  • throughstore.getState()Gets the state in the repository

This method is used by each component to get the common state used as data for the render view.

  • reducerIt acts as a warehouseManagement role, the operation status of each component must go through reducer.

Reducer as English word means reducer, reducer. This means manipulating state, managing behavior, and allowing components to retrieve state information from the repository in a more orderly and regular manner. Reducer is a function with two parameters: [state] [Action]. It receives the behavior object sent by the dispatch and sends it to the action, and then does corresponding processing. Action is an object, and the type attribute is guaranteed to identify the behavior. State carries the initial data of the repository, which is just a place to store data for the Reducer. Action returns the latest modified status information and changes the state in the repository.

  • throughstore.subscribe()To the event pool in the warehouseTo subscribe tomethods

In order to obtain the latest state, each component subscribes to the method of modifying its state in advance. Once the state changes in the warehouse, the component will re-render.

The store.subscribe() method executes a return value that removes the method from the event pool: unsubscribe()

  • throughstore.dispatch()distributedA task tells the Reducer to modify the state in the repository. The distribution is a bagtypeObject, throughtypeTo identify which state to change.

Finally, each component can be effectively updated in real time to achieve the management of the public state and communication between each component.

Handwritten Redux source code and optimization

  • Offer five methods
    • dispatch
    • subscribe
    • getState
    • replaceRedecer
    • [?observable]:observable
  • Redux source optimization
    • The user uses getState to clone a new state to prevent direct modification

    • For adding event pools, do reprocessing

    • Prevents direct state modification in the Reducer

      We know that the state was indeed modified by sending a task notice to reducer, but in order to update the state at a time when we operate the state, and not destroy the original state during the modification, so as to prevent confusion of the state, it is necessary to clone a new state. When we used Reducer, a new copy was also cloned.

      • Hyperclone (recommended)
      • JSON.parse(JSON.stringify(xxx))
    • We improve performance by not notifying methods in the event pool to execute when the state is not updated. Use deep comparisons.

// Optimize a deep cloneexport cloneDeep(obj){
    if(obj===null) return null;
    if(typeof obj! = ="function") return obj;
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return enw Date(obj);
    let clone  = new obj.constructor;
    Object.keys(obj).forEach(item=>{
        clone[item] = cloneDeep(obj[item])
    })
    return clone
}
export function createStore(reducer){
if(typeof reducer! = ="function"){
    throw new TypeError("Expected the reducer to be a function "} //state Storage status listener Stores the event poollet state,
   isdispatch =false; listeners = []; // Get the statusgetState(){// Optimization 1: clone the returned information so that the read status information cannot be modified directly based on the object. Xxreturn cloneDeep(state)} // Append methods to the event poolfunction subscribe(func){
        if(typeof! = ="function"){
            throw new Error('Expectted the listener to be a function '} // Optimization twoif(! listeners.includes(func)){ listeners = listeners.push(func); }return function unsubscribe(){ listeners.filter(item=>{ item! = =function})}} // Assign tasksfunction dispatch(action){
        if(func===null||typeof action! = ="object"){
            throw new Error(
            'Action must be plain objects.'+'Use custom middleware for async actions')}if(typeof action === 'undefined'){
            throw new Error(
            'Action may not have an undefined 'type' property'+'have you misspelled a constant? '} // Prevent state modification in reducer, no need to manually clone state, here you can deep clone stateletpreState = state; state = reducer(state,action); // Methods in Listeners are not notified if the four depth comparison optimization is not modifiedif(! compareDeep(preState,state){ listeners.forEach(item=>{ item(); } // Execute a dispatch to the state ({// do not conflict with the action. Type of the usertype:Symbol('INIT')})return {
        setState, subscribe, dispatch}} // Optimize four deep comparisonexport  compareDeep(val1,val2){
    let type1 = typeof val1,
        type2 = typeof val2;
    if(type1===null&& type2===null){
        return true
    }    
    if(type= = = 1"function"&&type2 = = ="function") {return val1.toString === val2.toString
    }
    if(type= = = 1"object"&&type2 = = ="object") {let ct1 = val1.costructor,
            ct2 = val2.constructor;
        if((ct1===RegExp&&ct1===RegExp)||(ct2===Date&&ct2===Date)){
               return val1.toString() === val2.toString()
        }
        let key1 = Object.keys(val1),
        key2 = Object.keys(val2);
        if(key1.length===key2.length){
            key1.forEach(item=>{
                let value1=val1[item],
                    value2=val2[item];
                let res = compareDeep(value1,value2);
                 if(! res)return res
            })
        }
        return false; } // The basic data type can be compared directly based on three equals signsreturn val1===val2
    
}
Copy the code

React-redux

React-redux is a redux-encapsulated react-redux state management library that does three big things:

  • Provide a Provider ancestor component that places the Store repository in context for child components to call
  • Provide connect methods to mount state to child components as properties. Convert the object type returned by Action-Creator to dispatch and mount it to the child component via properties.
  • Return the proxy component (which is also a function). Simply putting the currently proxied component as an argument in the returned function will help us add a “common state change rerender event method” to the event pool in the Redux container.

Mind mapping:

React-redux partial source code

import React from 'redux';
import PropTypes from 'prop-types';
const ThemeContext = React. creatContext();
export class Provider extends React.Component{
    static propTypes = {
        store:PropTypes.object.isRequired
    };
    render(){<ThemeContent value={{store:this.props. Store}}>export functionThe connect (mapStateToProps mapDispatchToProps) {/ / initialization parameterif(typeof mapStateToProps! = ="function"){
        mapStateToProps = state=>{
            return{}}}if(typeof mapDispatchToProps! = ="function") {if(mapDispatchToProps! ==null&& typeof mapDispatchToProps==='object') {let action = mapDispatchToProps;
            mapDispatchToProps = dispatch=>{
                letobj = {}; Object.keys(action).forEach(item=>{ obj[item] = (... args)=>{ dispatch(action[item](... args)) } })return obj;
            }
        }
        mapDispatchToProps = dispatch=>{
            return{}}}return function connectHOC(component){
        return class proxy texends React.Component{
            static contextType = ThemeContext;
            render() {return <component/>;
            }
            queryPros=()=>{
                let { store } = this.conext,
                    state = store.getState(),
                    dispatch = store.dispatch;
                return{... mapStateToProps(state); . mapDispatchToProps(dispatch) } }componentDidMount(){ this.context.store.subscribe(()=>{ this.forceUpdate(); })}}}}Copy the code

Working with middleware

conclusion

  • Master the Redux principle
  • Learn the operating principles of React-Redux
  • Working with Middleware