1. Introduction

Hi, I’m Wakawa. This is the eighth installment of the learning source architecture series. Overall structure this word seems to be a little big, let’s just consider the overall structure of the source code, is mainly to learn the overall structure of the code, do not delve into the implementation of other specific functions that are not the main line. This article looks at the actual repository code.

If someone talks about how to read the source code, it would be nice if you, who are reading the article, could recommend my source code series.

Learn the overall structure of the source code series of articles as follows:

1. Learn the overall architecture of jQuery source code and build its own JS class library 2. Learn underscore source code architecture and build your own functional programming library 3. Learn the overall architecture of LoDash source code and build your own functional programming class library 4. Learn the overall architecture of Sentry source code and build its own front-end exception monitoring SDK 5. Learn the overall architecture of VUEX source code and build your own state management library 6. 7. Learn the overall architecture of KOA source code, and analyze the koA Onion model principle and CO principle 8. Learn the overall architecture of Redux source code and deeply understand the principles of Redux and its middleware

Interested readers can click to read. Other source code is planned: Express, vue-Rotuer, react-redux and other source code, I do not know when to write (cry), welcome to continue to follow me (Ruogawa).

Source code articles, general reading is not high. Those who have the ability to understand, read themselves. Don’t want to see, dare not see will not go to see the source code. So my article, as far as possible to write so that want to see the source code and do not know how to see the reader can understand.

Reading this article you will learn:

  1. git subtreeManage sub-warehouse
  2. How to learnreduxThe source code
  3. reduxMiddleware Principles
  4. reduxThe variousAPIThe implementation of the
  5. vuexreduxThe contrast of
  6. , etc.

1.1 The best way to read this article

My story source warehouse git clone https://github.com/lxchuan12/redux-analysis.git clone, star: by the way I learn warehouse ^_^ redux of the source code. Follow the pace of debugging and sample code debugging, hands-on debugging with Chrome more impressive. Article long section of code do not have to look at, you can debug and then look at. See this kind of source code article a hundred times, may be better than their own debugging several times. Also welcome to add my wechat exchange ruochuan12.

2. Git subtree manages sub-repositories

Wrote a lot of source code articles, vuex, Axios, KOA etc are using a new repository to clone a copy of the source code in their own repository. Although the computer can pull up the latest code and see the original author’s Git information. But when I uploaded it to Github. The original repository author’s Git information is lost to the reader. So I found git submodules, but it wasn’t a good fit. Then we discovered git subtree.

Git subtree and NPM Package The NPM package is one-way. Git subtree is bidirectional.

Use Git Subtree to bidirectionally synchronize subprojects between Git projects

4.x (as of June 13, 2020, the latest version of 4.x branch is 4.0.5, master branch is TS, The branch was cloned into a sub-project of my project to keep git information.

The corresponding command is:

git subtree add --prefix=redux https://github.com/reduxjs/redux.git 4.x
Copy the code

3. Debug redux source code preparation

Before, I answered a question in Zhihu, Ruochuan: how to do if the front end does not understand the source code of the front end framework within a year? Recommended some materials, reading volume is good, you can have a look. There are four main points:

2. Search and refer to relevant articles with high praise; 3. Record what you don’t understand and refer to relevant documents. conclusion

It’s important to look at source code debugging, so every source code article I write describes it in detail. How to debug source code.

Breakpoint debugging tips: The assignment statement can be skipped by pressing F10 to see the return value. Function execution requires the breakpoint to press F11 to follow, or you can use comments and context to backtrack what the function does. For those that don’t need to look closely, press F8 to go to the next breakpoint to refresh and debug again. Press F5

Before debugging the source code, take a quick look at redux’s workflow to get an idea.

Redux workflow

3.1 Rollup Generate sourcemAP for easy debugging

Modify the rollup.config.js file to output the configuration to generate sourcemap.

// redux/rollup.config.js has been omitted
const sourcemap = {
  sourcemap: true.};

output: {  // ... . sourcemap,} Copy the code

Install dependencies

git clone http://github.com/lxchuan12/redux-analysis.git
cd redux-analysi/redux
npm i
npm run build
The sourcemap. map file will be generated in dist, es, lib.
Copy the code

Take a closer look at the redux/examples directory and redux/README.

I created “examples” under the root directory and copied the counter “redux/examples/counter-vanilla/index.html” to “examples/index.html”. Also copy the packaged redux/dist directory containing Sourcemap to the examples/dist directory.

Change the redux.js file of the script in index.html to the path in dist.

In order to differentiate and commissioning subsequent HTML file, I put the index. The HTML renamed index. 1. Redux. GetState. Dispatch. HTML.

# redux-analysis root directory
Install the NPM package to start the service
npm i -g http-server
cd examples
hs -p 5000
Copy the code

You can debug it happily. Can be directly clone git clone http://github.com/lxchuan12/redux-analysis.git my project. Local debugging, hands-on practice, easy to digest.

4. Learn redux source code by debugging counter examples

Then let’s look at examples/index. 1. Redux. GetState. Dispatch. The HTML file. Look at the HTML section first. I just wrote a couple of buttons. It’s easy.

<div>
    <p>
    Clicked: <span id="value">0</span> times
    <button id="increment">+</button>
    <button id="decrement">-</button>
 <button id="incrementIfOdd">Increment if odd</button>  <button id="incrementAsync">Increment async</button>  </p> </div> Copy the code

The JS part is also simpler. We declare a counter function, pass it to redux.createstore (counter), and get the result store, which is an object. The render method renders the number to the page. Subscribe with the render method of store. Subscribe (render). There is also the store.dispatch({type: ‘INCREMENT’}) method, which triggers the Render method when called to store.dispatch. This implements a counter.

function counter(state, action) {
    if (typeof state === 'undefined') {
        return 0
    }

 switch (action.type) {  case 'INCREMENT':  return state + 1  case 'DECREMENT':  return state - 1  default:  return state  } }  var store = Redux.createStore(counter) var valueEl = document.getElementById('value')  function render() {  valueEl.innerHTML = store.getState().toString() } render() store.subscribe(render)  document.getElementById('increment') .addEventListener('click'.function () {  store.dispatch({ type: 'INCREMENT' }) })  // omit some temporarily invalid code... Copy the code

Think: looking at this code, where would you break it to debug?

// There are four breakpoints to view
/ / 1.
var store = Redux.createStore(counter)
/ / 2.
function render() {
valueEl.innerHTML = store.getState().toString() } render() / / 3. store.subscribe(render) / / 4. store.dispatch({ type: 'INCREMENT' }) Copy the code
Redux debugger figure

The right Scope in the figure, if you need to pay attention to it sometimes, will display variables such as closures, global environment, current environment, etc., as well as specific code locations such as functions, which can help you understand the code.

Breakpoint debugging, press F5 to refresh the page, press F8, mouse over Redux and Store.

You can see that there are several methods on Redux. Respectively is:

  • __DO_NOT_USE__ActionTypes: {INIT: “@@redux/INITu.v.d.u.6.r”, REPLACE: “@@redux/REPLACEg.u.u.7.c”, PROBE_UNKNOWN_ACTION: ƒ}
  • ApplyMiddleware: the ƒ applyMiddleware() function is an enhancer that combines multiple middleware and ultimately enhances itstore.dispatchThe function,dispatch, all middleware can be executed in tandem.
  • BindActionCreators: ƒ bindActionCreators(actionCreators, Dispatch) generates actions for other libraries, such asreact-redux.
  • CombineReducers: ƒ combineReducers(Reducersreducers, returns a totalreducerFunction.
  • Compose: ƒ compose() Combine several functions from right to left, for example: compose(f, g, h) args) => f(g(h(… args))).
  • CreateStore: ƒ createStore(Reducer, preloadedState, enhancer) has been generatedstoreobject

There are a couple of ways to look at store. Respectively is:

  • ƒ dispatch(ActionsubscribeThe collected functions are iterated and executed in turn
  • Subscribe: ƒ subscribe(listener) The subscription collection function exists in an array and is waiting to be triggereddispatchDo it in turn. Returns an unsubscribe function that can unsubscribe listening.
  • GetState: ƒ getState() ExistscreateStoreThe object of the internal closure of a function.
  • ReplaceReducer: ƒ replaceReducer(nextReducerreduxDeveloper tools to compare the similarities and differences between the current and last operation. It’s kind of like time travel.
  • Symbol (observables) : ƒ observables ()

This is the API in the official documentation redux.org.js.

I won’t delve into the implementation of each API for now. Repress F5 to refresh the page, breakpoint to var Store = redux.createstore (counter). Keep pressing F11 to go through the main process.

4.1 Redux. CreateSotre

The createStore function returns a store containing methods such as Dispatch, subscribe, getState, and replaceReducer.

// Omit some code
export default function createStore(reducer, preloadedState, enhancer) {
    // omit parameter checksum substitution
    // Current Reducer function
    let currentReducer = reducer
 / / the current state  let currentState = preloadedState  // The current listener array function  let currentListeners = []  // Listen to the array function next  let nextListeners = currentListeners  // Whether it is in dispatch  let isDispatching = false  function ensureCanMutateNextListeners() {  if (nextListeners === currentListeners) {  nextListeners = currentListeners.slice()  }  }  function getState() {  return currentState  }  function subscribe(listener) {}  function dispatch(action) {}  function replaceReducer(nextReducer) {}  function observable() {}  // ActionTypes.INIT @@redux/INITu.v.d.u.6.r  dispatch({ type: ActionTypes.INIT })  return {  dispatch,  subscribe,  getState,  replaceReducer,  [$observable]: observable  } } Copy the code

4.2 store. Dispatch (action)

function dispatch(action) {
    // Check whether the action is an object
    if(! isPlainObject(action)) {      throw new Error(
        'Actions must be plain objects. ' +
 'Use custom middleware for async actions.'  )  }  // Check whether action.type exists or not  if (typeof action.type === 'undefined') {  throw new Error(  'Actions may not have an undefined "type" property. ' +  'Have you misspelled a constant? '  )  }  // If no, an error is reported  if (isDispatching) {  throw new Error('Reducers may not dispatch actions.')  }   try {  isDispatching = true  currentState = currentReducer(currentState, action)  } finally {  // Set to false after the call  isDispatching = false  }  // Call the collected functions one by one  const listeners = (currentListeners = nextListeners)  for (let i = 0; i < listeners.length; i++) {  const listener = listeners[i]  listener()  }  // Finally returns action  return action  } Copy the code
var store = Redux.createStore(counter)
Copy the code

The above debugging the sentence.

Continue to press F11 to debug.

function render() {
    valueEl.innerHTML = store.getState().toString()
}
render()
Copy the code

4.3 store. GetState ()

The getState function is simpler to implement.

function getState() {
    // If the dispatch is in progress, an error is reported
    if (isDispatching) {
        throw new Error(
        'You may not call store.getState() while the reducer is executing. ' +
 'The reducer has already received the state as an argument. ' +  'Pass it down from the top reducer instead of reading it from the store.'  )  }  // Return the current state  return currentState } Copy the code

4.4 store. The subscribe (the listener)

Subscription listener function, stored in an array, iterated at store.dispatch(action).

function subscribe(listener) {
    // Subscription validation is not a function error
    if (typeoflistener ! = ='function') {
      throw new Error('Expected the listener to be a function.')
    }
 // In dispatch, an error is reported  if (isDispatching) {  throw new Error(  'You may not call store.subscribe() while the reducer is executing. ' +  'If you would like to be notified after the store has been updated, subscribe from a ' +  'component and invoke store.getState() in the callback to access the latest state. ' +  'See https://redux.js.org/api-reference/store#subscribelistener for more details.'  )  }  // Subscribe to true  let isSubscribed = true   ensureCanMutateNextListeners()  nextListeners.push(listener)   // Returns an unsubscribe function  return function unsubscribe() {  if(! isSubscribed) { return  }  // An error is reported when the dispatch is in progress  if (isDispatching) {  throw new Error(  'You may not unsubscribe from a store listener while the reducer is executing. ' +  'See https://redux.js.org/api-reference/store#subscribelistener for more details.'  )  }  // Subscribe to false  isSubscribed = false   ensureCanMutateNextListeners()  // Find the current listener function  const index = nextListeners.indexOf(listener)  // Delete from the array  nextListeners.splice(index, 1)  currentListeners = null  }  } Copy the code

At this point, we are done debugging and learning the source code of Redux.createSotre, store.dispatch, Store. getState, and Store. subscribe.

Next, we write a middleware example to debug middleware related source code.

5. Redux middleware related source code

Middleware is the focus, and interviewers often ask this question.

5.1 Redux. ApplyMiddleware (… middlewares)

5.1.1 Preparing for Logger example debugging

To debug redux. applyMiddleware(… Middlewares), I am examples/js/middlewares logger. Example. Js logger write a simple example. There are three logger1, logger2, and logger3 functions. Since they are all similar, I will only show logger1 functions here.

// examples/js/middlewares.logger.example.js
function logger1({ getState }) {
  return next= > action= > {
      console.log('will dispatch--1--next, action:', next, action)

 // Call the next dispatch method in the middleware chain.  const returnValue = next(action)   console.log('state after dispatch--1', getState())   // This will likely be the action itself, unless  // a middleware further in chain changed it.  return returnValue  } } // omit logger2, logger3 Copy the code

Logger middleware functions also do simple things, returning two layers of functions. Next is the next middleware function that returns the result. I use arrow functions for Logger1 and normal functions for Logger2 to make sense to the reader.

With that in mind, let’s look at debugging Redux. ApplyMiddleware (… Middlewares)) source.

cd redux-analysis && hs -p 5000
NPM I-g HTTP-server
Copy the code

Open http://localhost:5000/examples/index.2.redux.applyMiddleware.compose.html, press F12 open the console,

Click the plus operation +1 to display the result.

Redux middleware callback attempt

As you can see from the figure, next is the next function. 1-2-3, 3-2-1.

This is often referred to as middleware, faceted programming (AOP).

Middleware diagram

Next debug, break points on the following statements and any points you feel are important.

// examples/index.2.redux.applyMiddleware.compose.html
var store = Redux.createStore(counter, Redux.applyMiddleware(logger1, logger2,  logger3))
Copy the code

5.1.2 Redux. ApplyMiddleware (… Middlewares) source

// redux/src/applyMiddleware.js
/ * **...* @param {... Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware. * / export default function applyMiddleware(. middlewares) {  return createStore= > (. args) = > {  conststore = createStore(... args) let dispatch = (a)= > {  throw new Error(  'Dispatching while constructing your middleware is not allowed. ' +  'Other middleware would not be applied to this dispatch.'  )  }   const middlewareAPI = {  getState: store.getState,  dispatch: (. args) = >dispatch(... args) }  const chain = middlewares.map(middleware= > middleware(middlewareAPI)) dispatch = compose(... chain)(store.dispatch)  return { . store, dispatch  }  } } Copy the code
// redux/src/createStore.js
export default function createStore(reducer, preloadedState, enhancer) {
  // omit parameter verification
  // If the second parameter 'preloadedState' is a function and the third parameter 'enhancer' is undefined, swap them.
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
 enhancer = preloadedState  preloadedState = undefined  }   if (typeofenhancer ! = ='undefined') {  if (typeofenhancer ! = ='function') {  throw new Error('Expected the enhancer to be a function.')  }  // enhancer is the function returned by 'Redux. ApplyMiddleware'  // The args of createStore is reducer, preloadedState  / * ** createStore => (... args) => {const store = createStore(... args) return { . store, dispatch,  }  } * * /// Finally returns the enhanced store object. return enhancer(createStore)(reducer, preloadedState)  } // omit subsequent code} Copy the code

Put the received middleware functions logger1, Logger2, and Logger3 into the Middlewares array. Redux. ApplyMiddleware finally returns two levels of functionality. Middleware functions are mixed in with the arguments getState and Dispatch.

// examples/index.2.redux.applyMiddleware.compose.html
var store = Redux.createStore(counter, Redux.applyMiddleware(logger1, logger2,  logger3))
Copy the code

This last sentence returns a store object that has been enhanced with Dispatch.

The enhanced dispatch function, however, uses the Redux.compose(… Functions) are executed in series.

5.2 Redux.com pose (… functions)

export default function compose(. funcs) {
  if (funcs.length === 0) {
    return arg= > arg
  }

 if (funcs.length === 1) {  return funcs[0]  }   return funcs.reduce((a, b) = > (. args) = >a(b(... args)))} Copy the code
// applyMiddleware.js
dispatch = compose(... chain)(store.dispatch)// compose
funcs.reduce((a, b) = > (. args) = >a(b(... args)))Copy the code

These two sentences may not be so easy to understand, you can break the debugging several times. I converted the arrow function to a normal function.

funcs.reduce(function(a, b){
  return function(. args){
    returna(b(... args));  };
});
Copy the code

Compose (f, g, h) : compose(f, g, h) : compose(f, g, h) args) => f(g(h(… args))).

5.2.1 Evolution of compose function

See Redux.com pose (… After the source, or do not understand, do not hurry do not panic, eat eggs and soup. To take a closer look at how this evolved, start with a brief look at the following requirements.

Take a number, multiply it by 10, add 10, subtract 2.

It’s simple to implement.

const calc = (num) = > num * 10 + 10 - 2;
calc(10); / / 108
Copy the code

But there’s a problem with writing it this way, it’s not very scalable, so let’s say I want to multiply by 10 and I print it out. To facilitate expansion, we write three functions separately.

const multiply = (x) = > {
   const result = x * 10;
   console.log(result);
   return result;
};
const add = (y) = > y + 10; const minus = (z) = > z - 2;  // Calculate the result console.log(minus(add(multiply(10)))); / / 100 / / 108 // Then we can calculate the three functions. Copy the code

Let’s implement a relatively general function that computes the results of these three functions.

const compose = (f, g, h) = > {
  return function(x){
    return f(g(h(x)));
  }
}
const calc = compose(minus, add, multiply); console.log(calc(10)); / / 100 / / 108 Copy the code

There is still a problem with this, only three functions are supported. I want to support multiple functions. We learned that the reduce method of arrays can do just that. The previous function

// We often use reduce to calculate the sum of numeric arrays
[1.2.3.4.5].reduce((pre, item, index, arr) = > {
  console.log('(pre, item, index, arr)', pre, item, index, arr);
  // (pre, item, index, arr) 1 2 1 (5) [1, 2, 3, 4, 5]
  // (pre, item, index, arr) 3 3 2 (5) [1, 2, 3, 4, 5]
 // (pre, item, index, arr) 6 4 3 (5) [1, 2, 3, 4, 5]  // (pre, item, index, arr) 10 5 4 (5) [1, 2, 3, 4, 5]  return pre + item; }); / / 15 Copy the code

Pre is the last return value, in this case the value 1,3,6,10. In the next example, anonymous functions.

function(x){
  return a(b(x));
}
Copy the code

Item is 2,3,4,5, and in the next example minus, add, multiply.

const compose = (. funcs) = > {
  return funcs.reduce((a, b) = > {
    return function(x){
      return a(b(x));
    }
 }) } const calc = compose(minus, add, multiply); console.log(calc(10)); / / 100 / / 108 Copy the code

The Redux.com pose (… Functions), except that the middleware returns a two-layer function.

So the next functions are returned, and they are executed in string, forming the middleware onion model. They say a picture is worth a thousand words. I drew a relatively simple schematic of the Redux middleware.

reduxMiddleware schematic

If you are not quite clear, it is recommended to follow the examples I give, debugging more.

cd redux-analysis && hs -p 5000
NPM I-g HTTP-server
Copy the code

Open http://localhost:5000/examples/index.3.html, press F12 open the debug console.

5.2.2 Implementation of front-end framework compose function

Lodash’s implementation of the compose function in the source code is similar to arrayReduce, but is an internal implementation of arrayReduce

To quote from my article: Learn loDash source code architecture

/ / lodash source code
function baseWrapperValue(value, actions) {
 var result = value;
 / / if it is lazyWrapper instance, call the lazyWrapper. Prototype. Value method, namely lazyValue method
 if (result instanceof LazyWrapper) {
 result = result.value();  }  // Similar to [].reduce(), passing the result returned by the previous function as an argument to the next function  return arrayReduce(actions, function(result, action) {  return action.func.apply(action.thisArg, arrayPush([result], action.args));  }, result); } Copy the code

Koa-compose source code also has an implementation of the compose function. The implementation is a loop with a promise. Because the code is relatively long I will omit, specifically see the link If Chuan: learn the overall structure of KOA source code, analysis of KOA Onion model principle and CO principle section koA-compose source code (Onion model implementation)

6. Redux.combineReducers(reducers)

Open http://localhost:5000/examples/index.4.html, press F12 open the console, according to the given example, Debug the following concrete implementation of Redux.combineReducers(Reducers) and Redux.bindActionCreators(actionCreators, Dispatch). Since the article is long, these two functions will not be explained in so much detail.

The combineReducers function is simply a combination of multiple reducer functions.

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers)
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]
  // Omit some development environment judgment code...   if (typeof reducers[key] === 'function') {  finalReducers[key] = reducers[key]  }  }   // Get the final finalReducerKeys after some processing  const finalReducerKeys = Object.keys(finalReducers)   // Omit some development environment judgment code...   return function combination(state = {}, action) {  / /... Omit some of the judgments of the development environment   // Record whether state has been changed before and after using the hasChanged variable  let hasChanged = false  // Declare the object to store the next state  const nextState = {}  / / traverse finalReducerKeys  for (let i = 0; i < finalReducerKeys.length; i++) {  const key = finalReducerKeys[i]  const reducer = finalReducers[key]  const previousStateForKey = state[key]  / / reducer for execution  const nextStateForKey = reducer(previousStateForKey, action)   // omit fault-tolerant code...   nextState[key] = nextStateForKey  // If the two key comparisons are not equal, the change will occur hasChanged = hasChanged || nextStateForKey ! == previousStateForKey }  // The final keys array comparison is not equal to change  hasChanged = hasChanged || finalReducerKeys.length ! = =Object.keys(state).length  return hasChanged ? nextState : state  } } Copy the code

7. Redux.bindActionCreators(actionCreators, dispatch)

If the first argument is a function, return a function. If it is an object, the assignment is iterated, resulting in the boundActionCreators object.

function bindActionCreator(actionCreator, dispatch) {
  return function() {
    return dispatch(actionCreator.apply(this.arguments))
  }
}
 export default function bindActionCreators(actionCreators, dispatch) {  if (typeof actionCreators === 'function') {  return bindActionCreator(actionCreators, dispatch)  }   / /... Omit some fault-tolerant judgments   const boundActionCreators = {}  for (const key in actionCreators) {  const actionCreator = actionCreators[key]  if (typeof actionCreator === 'function') {  boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)  }  }  return boundActionCreators } Copy the code

Redux provides API in addition to store. ReplaceReducer (nextReducer) did not analyze, other analysis.

8. A simple comparison of Vuex and Redux

8.1 Source code implementation form

In terms of source code implementation, Vuex source code mainly uses constructors, while Redux is multi-functional programming, closure.

8.2 the coupling

Vuex is strongly coupled to VUE and cannot be used without VUE. Redux has nothing to do with React, so it can be used with applets, jQuery, etc. If you need to use react with react, you also need to use the React-Redux library.

8.3 extensions

// Logger plug-in, specific implementation omitted
function logger (store) {
  console.log('store', store);
}
// passed as an array
new Vuex.Store({  state,  getters,  actions,  mutations,  plugins: process.env.NODE_ENV ! = ='production'  ? [logger]  : [] }) // Vuex source plugin implementation class Store{  constructor() { // Pass the entire vuex instance object store to the plugin for use  plugins.forEach(plugin= > plugin(this))  } } Copy the code

Vuex implements extensions in plug-in form, while Redux is middleware form. Redux’s middleware is AOP (faceted programming), and redux.applymiddleware () in Redux is actually an enhancer, so users can implement enhancers as well, so the Redux ecosystem is thriving.

8.4 Ease of use

Vuex is relatively easy to get started, while Redux is more difficult. Redux involves functional programming, higher-order functions, pure functions, and so on.

9. To summarize

This article mainly through the step by step debugging of the way to tell about redux source code concrete implementation. Designed to teach readers to debug source code, not afraid of source code.

Interviewers often like to write a redux middleware test, talk about the principle of Redux middleware.

function logger1({ getState }) {
  return next= > action= > {
      const returnValue = next(action)
      return returnValue
  }
} Copy the code
const compose = (. funcs) = > {
  if (funcs.length === 0) {
    return arg= > arg
  }

 if (funcs.length === 1) {  return funcs[0]  }   // Arrow function  // return funcs.reduce((a, b) => (... args) => a(b(... args)))  return funcs.reduce((a, b) = > {  return function(x){  return a(b(x));  }  }) } Copy the code
constenhancerStore = Redux.create(reducer, Redux.applyMiddleware(logger1, ...) )enhancerStore.dispatch(action)
Copy the code

The user triggers enhancerStore.dispatch(Action) as enhanced, which is actually the first middleware function, next in the middle is the next middleware function, and finally next is the unenhanced Store.dispatch(action).

Finally, let’s look at ZhangreduxWork flow chart

It makes a little bit more sense.

If you find something wrong or can be improved, or if you don’t make it clear, you are welcome to comment. In addition, I think the writing is good and helpful to you. You can like, comment, forward and share, which is also a kind of support for me. Thank you very much. If someone talks about how to read the source code, it would be nice if you, who are reading the article, could recommend my source code series.

Recommended reading

Redux (1) : React Redux: How to change a shared state gracefully, 6 sections in total, very recommended, although I have read the React Little Book for a long time, now I will read it again and get a good result. Very recommended redux Chinese document redux English document if chuan learning redux source code warehouse

Another series

Can you emulate the call and apply methods of JS? Can you emulate the new operator of JS

about

Author: Often in the name of ruochuan mixed traces in rivers and lakes. The front road lovers | | PPT know little, only good study. Ruochuan’s blog, using Vuepress reconstruction, reading experience may be better dig column, welcome to follow ~ SegmentFault front view column, welcome to follow ~ Zhihu front view column, welcome to follow ~ Language finch front view column, new language Finch column, welcome to follow ~ github blog, Related source code and resources are put here, ask a star^_^~

Welcome to add wechat communication wechat official account

May be more interesting wechat public number, long press scan code attention. You are welcome to join ruochuan12 in wechat for long-term communication and learning

If sichuan vision

This article is formatted using MDNICE