Note source: Hook Education – big front end employment Training camp

Content: Notes, thoughts and experiences in the process of learning

Tip: project actual combat article resources can not be uploaded, only for reference

Redux principle

Core Logic/API-ceratestore ()

Parameter:

  • Reducer function
  • PreloadedState: Store state of pre-storage, that is, original state
  • Enhancer (adding store functionality), discussed later

Return object:

  • GetState: Used to get the status
  • Dispatch: triggers operations related to instructions
  • Subscribe: A state of subscription that can be called multiple times

Simulate cerateStore and use

// Simulate the cerateStore method
function cerateStore(reducer, preloadedState) {
  // Get the initial state
  let data = preloadedState
  / / subscriber
  let listeners = []
  // Get the state method
  function getState() {
    // Return to status directly
    return data
  }
  // instruction firing method
  function dispatch(action) {
    // Call argument returns the result
    data = reducer(data, action)
    // Traverse the subscriber to trigger the subscriber
    for (const listen of listeners) {
      listen()
    }
  }
  // Add subscriber method
  function subscribe(cb) {
    // cb is the callback function to be triggered by the subscriber
    listeners.push(cb)
  }
  // Returns an object composed of three methods
  return { getState, dispatch, subscribe }
}
Copy the code
<body>
  <! -- -- -- > structure
  <button id="up">+ 1</button>
  <span id="num">0</span>
  <button id="down">- 1</button>
  
  <! -- Introducing cerateStore -->
  <script src="./myRedux.js"></script>
  <script>
    // Create the cerateStore parameter - reducer
    function reducer(state, action) {
      // Return status according to the command
      switch (action.type) {
        case 'up':
          return state + 1
        case 'down':
          return state - 1
        default:
          return state
      }
    }

    / / create a store
    const store = cerateStore(reducer, 0)

    // Add subscribers
    store.subscribe(() = > {
      // Once triggered, change the state of inner to store
      document.getElementById('num').innerHTML = store.getState()
    })

    // Add click events to both buttons, calling store.dispatch
    document.getElementById('up').onclick = function () {
      store.dispatch({ type: 'up'})}document.getElementById('down').onclick = function () {
      store.dispatch({ type: 'down'})}</script>
</body>
Copy the code

Parameter type constraints – Improved cerateStore

Use throw new Error () for Error handling

  • The limit parameter reducer must be a function – Typof
  • The argument passed when calling Dispatch must be an object and must have a Type attribute
// Simulate the cerateStore method
function cerateStore(reducer, preloadedState) {
  Check whether reducer is a function directly
  if (typeofreducer ! = ='function') throw new Error('Reducer must be an object')
  // Get the initial state
  let data = preloadedState
  / / subscriber
  let listeners = []
  // Get the state method
  function getState() {
    // Return to status directly
    return data
  }
  // instruction firing method
  function dispatch(action) {
    // Call the function to determine whether it is an object
    if(! isPlainObject(action))throw new Error('Parameter must be an object')
    // Check whether there is a type attribute
    if (typeof action.type === 'undefined') throw new Error('Need to pass in the type attribute')
    // Call argument returns the result
    data = reducer(data, action)
    // Traverse the subscriber to trigger the subscriber
    for (const listen of listeners) {
      listen()
    }
  }
  // Add subscriber method
  function subscribe(cb) {
    // cb is the callback function to be triggered by the subscriber
    listeners.push(cb)
  }
  // Returns an object composed of three methods
  return { getState, dispatch, subscribe }
}

// Determine whether the object is non-empty
function isPlainObject(obj) {
  // Exclude other cases from the array
  if (typeofobj ! = ='object' || obj === null) return false
  // Based on the top-level prototype object and its own prototype object
  let proto = obj
  while (Object.getPrototypeOf(proto) ! =null) {
    proto = Object.getPrototypeOf(proto)
  }
  return proto === Object.getPrototypeOf(obj)
}
Copy the code

Implement Enhancer – Perfect cerateStore

Add an optional third parameter to the cerate function to enhance the returned store

  • It has to be a function, so judge before you use it
  • Enhancer If the criteria are met, then Enhancer is used to create a powerful store
  • If the conditions are not met, continue to create a common store in the original way
// Simulate the cerateStore method
function cerateStore(reducer, preloadedState, enhancer) {
  Check whether reducer is a function directly
  if (typeofreducer ! = ='function') throw new Error('Reducer must be an object')
  // Check whether enhancer is passed in
  if (typeofenhancer ! = ='undefined') {
    // Enhancer is passed to determine whether it is a function
    if (typeofenhancer ! = ='function')
      throw new Error('Enhancer must be a function')
    // Call the function for the function and pass in cerateStore as an argument
    // The function returns a function, which is called immediately
    // Pass reducer and preloadedState as parameters to the new function
    return enhancer(cerateStore)(reducer, preloadedState)
  }
  // Get the initial state
  let data = preloadedState
  / / subscriber
  let listeners = []
  // Get the state method
  function getState() {
    // Return to status directly
    return data
  }
  // instruction firing method
  function dispatch(action) {
    // Call the function to determine whether it is an object
    if(! isPlainObject(action))throw new Error('Parameter must be an object')
    // Check whether there is a type attribute
    if (typeof action.type === 'undefined') throw new Error('Need to pass in the type attribute')
    // Call argument returns the result
    data = reducer(data, action)
    // Traverse the subscriber to trigger the subscriber
    for (const listen of listeners) {
      listen()
    }
  }
  // Add subscriber method
  function subscribe(cb) {
    // cb is the callback function to be triggered by the subscriber
    listeners.push(cb)
  }
  // Returns an object composed of three methods
  return { getState, dispatch, subscribe }
}

// Determine whether the object is non-empty
function isPlainObject(obj) {
  // Exclude other cases from the array
  if (typeofobj ! = ='object' || obj === null) return false
  // Based on the top-level prototype object and its own prototype object
  let proto = obj
  while (Object.getPrototypeOf(proto) ! =null) {
    proto = Object.getPrototypeOf(proto)
  }
  return proto === Object.getPrototypeOf(obj)
}
Copy the code
<body>
  <! -- -- -- > structure
  <button id="up">+ 1</button>
  <span id="num">0</span>
  <button id="down">- 1</button>
  <! -- Introducing cerateStore -->
  <script src="./myRedux.js"></script>
  <script>
    // Create the cerateStore parameter - reducer
    function reducer(state, action) {
      // Return status according to the command
      switch (action.type) {
        case 'up':
          return state + 1
        case 'down':
          return state - 1
        default:
          return state
      }
    }
    // Create the cerateStore parameter -enhancer
    function enhancer(cerateStore) {
      // Return a new function
      return function (reducer, preloadedState) {
        // Call cerateStore to create a normal store
        let store = cerateStore(reducer, preloadedState)
        // Select dispatch from dispatch
        const dispatch = store.dispatch
        // Create a new dispatch to replace the old one. Action is the argument passed when called
        function _dispatch_(action) {
          // If a function is passed, execute the function and pass the original dispatch to the function
          if (typeof action === 'function') {
            return action(dispatch)
          }
          // If the function does not call dispatch directly
          dispatch(action)
        }
        // Return to the modified store
        return { ...store, dispatch: _dispatch_ }
      }
    }
    / / create a store
    const store = cerateStore(reducer, 0, enhancer)
    // Add subscribers
    store.subscribe(() = > {
      // Once triggered, change the state of inner to store
      document.getElementById('num').innerHTML = store.getState()
    })

    // Add click events to both buttons, calling store.dispatch
    document.getElementById('up').onclick = function () {
      // Call dispatch to pass a function
      store.dispatch(dispatch= > {
        // Function internal logic
        setTimeout(() = > {
          // Finally call the dispatch that should have been executed
          dispatch({ type: 'up'})},2000)})}document.getElementById('down').onclick = function () {
      // Instead of passing in the function, pass in the dispatch that needs to be executed
      store.dispatch({ type: 'down'})}</script>
</body>
Copy the code

Carding:

  • The third argument to cerateStore creates a store that is more powerful than a regular store
  • Check whether enhancer meets the requirements before using it
  • If it meets the requirements, it will be called directly and the original cerateStore will be passed in
  • Enhancer returns a new function, which is called immediately and accepts the first two values of cerateStore. At this point, cerateStore, Reducer, and preloadedState are passed to enhancer
  • The new function creates a plain store through cerateStore, which can be used directly
  • If we want to dispatch on a regular store, we need to create a new dispach to replace the old dispatch
  • Because the new dispach does not have the old dispach logic, the old dispach logic is still called when the logic is needed

This is how middleware is implemented

Middleware implementation principle – applyMiddleware

The middleware intercepts the action after it is sent and before the reducer receives it

At the heart of the middleware is the enhanced Dispatch method, which, when multiple middleware are present, executes in sequence before triggering the action

// Middleware 1
// Store: emasculated version of store, including only getState and Dispatch
// Next: next middleware, or dispatch if the current is the last middleware
// Parameter action: is the triggered action
function one(store) {
  return function (next) {
    return function (action) {
      console.log('One middleware executed')
      next(action)
    }
  }
}
Copy the code
// Middleware 2
// Store: emasculated version of store, including only getState and Dispatch
// Next: next middleware, or dispatch if the current is the last middleware
// Parameter action: is the triggered action
function tow(store) {
  return function (next) {
    return function (action) {
      console.log('Tow middleware executes')
      next(action)
    }
  }
}
Copy the code
The store is created here to import the middleware directly using the middleware function<body>
  <! -- -- -- > structure
  <button id="up">+ 1</button>
  <span id="num">0</span>
  <button id="down">- 1</button>
  <! -- Introducing cerateStore -->
  <script src="./myRedux.js"></script>
  <! -- Introducing middleware -->
  <script src="./middleware/one.js"></script>
  <script src="./middleware/tow.js"></script>
  <script>
    // Create the cerateStore parameter - reducer
    function reducer(state, action) {
      // Return status according to the command
      switch (action.type) {
        case 'up':
          return state + 1
        case 'down':
          return state - 1
        default:
          return state
      }
    }
    // Create the cerateStore parameter -enhancer
    function enhancer(cerateStore) {
      // Return a new function
      return function (reducer, preloadedState) {
        // Call cerateStore to create a normal store
        let store = cerateStore(reducer, preloadedState)
        // Select dispatch from dispatch
        const dispatch = store.dispatch
        // Create a new dispatch to replace the old one. Action is the argument passed when called
        function _dispatch_(action) {
          // If a function is passed, execute the function and pass the original dispatch to the function
          if (typeof action === 'function') {
            return action(dispatch)
          }
          // If the function does not call dispatch directly
          dispatch(action)
        }
        // Return to the modified store
        return { ...store, dispatch: _dispatch_ }
      }
    }
    // Create a store, which uses the middleware function to bring in two middleware
    const store = cerateStore(reducer, 0, applyMiddleware(one, tow))
    // Add subscribers
    store.subscribe(() = > {
      // Once triggered, change the state of inner to store
      document.getElementById('num').innerHTML = store.getState()
    })

    // Add click events to both buttons, calling store.dispatch
    document.getElementById('up').onclick = function () {
      store.dispatch({ type: 'up'})}document.getElementById('down').onclick = function () {
      // Instead of passing in the function, pass in the dispatch that needs to be executed
      store.dispatch({ type: 'down'})}</script>
</body>
Copy the code
// Simulate the cerateStore method
function cerateStore(reducer, preloadedState, enhancer) {
  Check whether reducer is a function directly
  if (typeofreducer ! = ='function') throw new Error('Reducer must be an object')
  // Check whether enhancer is passed in
  if (typeofenhancer ! = ='undefined') {
    // Enhancer is passed to determine whether it is a function
    if (typeofenhancer ! = ='function')
      throw new Error('Enhancer must be a function')
    // Call the function for the function and pass in cerateStore as an argument
    // The function returns a function, which is called immediately
    // Pass reducer and preloadedState as parameters to the new function
    return enhancer(cerateStore)(reducer, preloadedState)
  }
  // Get the initial state
  let data = preloadedState
  / / subscriber
  let listeners = []
  // Get the state method
  function getState() {
    // Return to status directly
    return data
  }
  // instruction firing method
  function dispatch(action) {
    // Call the function to determine whether it is an object
    if(! isPlainObject(action))throw new Error('Parameter must be an object')
    // Check whether there is a type attribute
    if (typeof action.type === 'undefined') throw new Error('Need to pass in the type attribute')
    // Call argument returns the result
    data = reducer(data, action)
    // Traverse the subscriber to trigger the subscriber
    for (const listen of listeners) {
      listen()
    }
  }
  // Add subscriber method
  function subscribe(cb) {
    // cb is the callback function to be triggered by the subscriber
    listeners.push(cb)
  }
  // Returns an object composed of three methods
  return { getState, dispatch, subscribe }
}

// Determine whether the object is non-empty
function isPlainObject(obj) {
  // Exclude other cases from the array
  if (typeofobj ! = ='object' || obj === null) return false
  // Based on the top-level prototype object and its own prototype object
  let proto = obj
  while (Object.getPrototypeOf(proto) ! =null) {
    proto = Object.getPrototypeOf(proto)
  }
  return proto === Object.getPrototypeOf(obj)
}

// Middleware methods, using... Merges multiple parameters into an array
function applyMiddleware(. wares) {
  // As with Enhancer, you still need to create the basic store
  return function (cerateStore) {
    return function (reducer, preloadedState) {
      // Create store - basic
      let store = cerateStore(reducer, preloadedState)
      // Create a castrated version of store for import middleware
      let middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch,
      }
      // Executes all outermost middleware functions, returning an array of functions returned by the outermost middleware
      const chain = wares.map(ware= > ware(middlewareAPI))
      // Iterate through the array above, execute the second layer of middleware functions (destruct), pass the dispatch, and return
      constdispatch = compose(... chain)(store.dispatch)// Return to store and replace Dispatch
      return {
        ...store,
        dispatch,
      }
    }
  }
}

// Middleware layer 2 function execution
function compose() {
  // Takes an argument and converts it from a class array to an array
  const funcs = [...arguments]
  // Return the function, since store.dispatch is used, where dispatch is the next parameter in the middleware
  return function (dispatch) {
    // Execute the function backwards because the former middleware needs to use the third layer function returned by the latter middleware
    for (let i = funcs.length - 1; i >= 0; i--) {
      // Modify parameters to layer 3 functions of later middleware
      dispatch = funcs[i](dispatch)
    }
    // Returns the first middleware layer-2 function directly
    return dispatch
  }
}

Copy the code

bindActionCreators

The bindActionCreators method essentially encapsulates what would otherwise be a manual call to Dispatch by simply calling the corresponding method name of the bindActionCreators function

// Simulate the cerateStore method
function cerateStore(reducer, preloadedState, enhancer) {
  Check whether reducer is a function directly
  if (typeofreducer ! = ='function') throw new Error('Reducer must be an object')
  // Check whether enhancer is passed in
  if (typeofenhancer ! = ='undefined') {
    // Enhancer is passed to determine whether it is a function
    if (typeofenhancer ! = ='function')
      throw new Error('Enhancer must be a function')
    // Call the function for the function and pass in cerateStore as an argument
    // The function returns a function, which is called immediately
    // Pass reducer and preloadedState as parameters to the new function
    return enhancer(cerateStore)(reducer, preloadedState)
  }
  // Get the initial state
  let data = preloadedState
  / / subscriber
  let listeners = []
  // Get the state method
  function getState() {
    // Return to status directly
    return data
  }
  // instruction firing method
  function dispatch(action) {
    // Call the function to determine whether it is an object
    if(! isPlainObject(action))throw new Error('Parameter must be an object')
    // Check whether there is a type attribute
    if (typeof action.type === 'undefined') throw new Error('Need to pass in the type attribute')
    // Call argument returns the result
    data = reducer(data, action)
    // Traverse the subscriber to trigger the subscriber
    for (const listen of listeners) {
      listen()
    }
  }
  // Add subscriber method
  function subscribe(cb) {
    // cb is the callback function to be triggered by the subscriber
    listeners.push(cb)
  }
  // Returns an object composed of three methods
  return { getState, dispatch, subscribe }
}

// Determine whether the object is non-empty
function isPlainObject(obj) {
  // Exclude other cases from the array
  if (typeofobj ! = ='object' || obj === null) return false
  // Based on the top-level prototype object and its own prototype object
  let proto = obj
  while (Object.getPrototypeOf(proto) ! =null) {
    proto = Object.getPrototypeOf(proto)
  }
  return proto === Object.getPrototypeOf(obj)
}

// Middleware methods, using... Merges multiple parameters into an array
function applyMiddleware(. wares) {
  // As with Enhancer, you still need to create the basic store
  return function (cerateStore) {
    return function (reducer, preloadedState) {
      // Create store - basic
      let store = cerateStore(reducer, preloadedState)
      // Create a castrated version of store for import middleware
      let middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch,
      }
      // Executes all outermost middleware functions, returning an array of functions returned by the outermost middleware
      const chain = wares.map(ware= > ware(middlewareAPI))
      // Iterate through the array above, execute the second layer of middleware functions (destruct), pass the dispatch, and return
      constdispatch = compose(... chain)(store.dispatch)// Return to store and replace Dispatch
      return {
        ...store,
        dispatch,
      }
    }
  }
}

// Middleware layer 2 function execution
function compose() {
  // Takes an argument and converts it from a class array to an array
  const funcs = [...arguments]
  // Return the function, since store.dispatch is used, where dispatch is the next parameter in the middleware
  return function (dispatch) {
    // Execute the function backwards because the former middleware needs to use the third layer function returned by the latter middleware
    for (let i = funcs.length - 1; i >= 0; i--) {
      // Modify parameters to layer 3 functions of later middleware
      dispatch = funcs[i](dispatch)
    }
    // Returns the first middleware layer-2 function directly
    return dispatch
  }
}

// bindActionCreators handles the action
// Parameter 1: action collection
// Parameter 2: dispatch
function bindActionCreators(arr, diapatch) {
  // Create an empty object
  const actions = {}
  / / traverse the action
  for (let key in arr) {
    // Add attributes to the object, corresponding to action
    actions[key] = function () {
      // Notice the use of the action return value
      diapatch(arr[key]())
    }
  }
  // Returns the processed action directly
  return actions
}
Copy the code
<body>
  <! -- -- -- > structure
  <button id="up">+ 1</button>
  <span id="num">0</span>
  <button id="down">- 1</button>
  <! -- Introducing cerateStore -->
  <script src="./myRedux.js"></script>
  <! -- Introducing middleware -->
  <script src="./middleware/one.js"></script>
  <script src="./middleware/tow.js"></script>
  <script>
    // Create the cerateStore parameter - reducer
    function reducer(state, action) {
      // Return status according to the command
      switch (action.type) {
        case 'up':
          return state + 1
        case 'down':
          return state - 1
        default:
          return state
      }
    }
    // Create the cerateStore parameter -enhancer
    function enhancer(cerateStore) {
      // Return a new function
      return function (reducer, preloadedState) {
        // Call cerateStore to create a normal store
        let store = cerateStore(reducer, preloadedState)
        // Select dispatch from dispatch
        const dispatch = store.dispatch
        // Create a new dispatch to replace the old one. Action is the argument passed when called
        function _dispatch_(action) {
          // If a function is passed, execute the function and pass the original dispatch to the function
          if (typeof action === 'function') {
            return action(dispatch)
          }
          // If the function does not call dispatch directly
          dispatch(action)
        }
        // Return to the modified store
        return { ...store, dispatch: _dispatch_ }
      }
    }
    // Create a store, which uses the middleware function to bring in two middleware
    const store = cerateStore(reducer, 0, applyMiddleware(one, tow))
    // Add subscribers
    store.subscribe(() = > {
      // Once triggered, change the state of inner to store
      document.getElementById('num').innerHTML = store.getState()
    })
    // Use bindActionCreators to handle the action
    const actions = bindActionCreators({ up, down }, store.dispatch)
    // Both functions return action information directly to Dispatch
    function up() {
      return { type: 'up'}}function down() {
      return { type: 'down'}}// Add click events to both buttons, calling store.dispatch
    document.getElementById('up').onclick = function () {
      // store.dispatch({ type: 'up' })
      // Just call the processed method name of bindActionCreators
      actions.up()
    }
    document.getElementById('down').onclick = function () {
      // store.dispatch({ type: 'down' })
      // Just call the processed method name of bindActionCreators
      actions.down()
    }
  </script>
</body>
Copy the code

CombineReducers – Merge reducer

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <! -- -- -- > structure
    <button id="up">+ 1</button>
    <span id="num">0</span>
    <button id="down">- 1</button>
    <! -- Introducing cerateStore -->
    <script src="./myRedux.js"></script>
    <! -- Introducing middleware -->
    <script src="./middleware/one.js"></script>
    <script src="./middleware/tow.js"></script>
    <script>
      // Create the cerateStore parameter - reducer
      function reducer(state, action) {
        // Return status according to the command
        switch (action.type) {
          case 'up':
            return state + 1
          case 'down':
            return state - 1
          default:
            return state
        }
      }
      // Create the cerateStore parameter -enhancer
      function enhancer(cerateStore) {
        // Return a new function
        return function (reducer, preloadedState) {
          // Call cerateStore to create a normal store
          let store = cerateStore(reducer, preloadedState)
          // Select dispatch from dispatch
          const dispatch = store.dispatch
          // Create a new dispatch to replace the old one. Action is the argument passed when called
          function _dispatch_(action) {
            // If a function is passed, execute the function and pass the original dispatch to the function
            if (typeof action === 'function') {
              return action(dispatch)
            }
            // If the function does not call dispatch directly
            dispatch(action)
          }
          // Return to the modified store
          return { ...store, dispatch: _dispatch_ }
        }
      }
      Merge the reducer with combineReducers
      const rootReducer = combineReducers({ num: reducer })
      // Create a store, which uses the middleware function to bring in two middleware
      const store = cerateStore(
        // Use the merged reducer
        rootReducer,
        { num: 0 },
        applyMiddleware(one, tow)
      )
      // Add subscribers
      store.subscribe(() = > {
        // Once triggered, change the state of inner to store because reducer merged and needed to call the attributes
        document.getElementById('num').innerHTML = store.getState().num
      })
      // Use bindActionCreators to handle the action
      const actions = bindActionCreators({ up, down }, store.dispatch)
      // Both functions return action information directly to Dispatch
      function up() {
        return { type: 'up'}}function down() {
        return { type: 'down'}}// Add click events to both buttons, calling store.dispatch
      document.getElementById('up').onclick = function () {
        // store.dispatch({ type: 'up' })
        // Just call the processed method name of bindActionCreators
        actions.up()
      }
      document.getElementById('down').onclick = function () {
        // store.dispatch({ type: 'down' })
        // Just call the processed method name of bindActionCreators
        actions.down()
      }
    </script>
  </body>
</html>
Copy the code
// Simulate the cerateStore method
function cerateStore(reducer, preloadedState, enhancer) {
  Check whether reducer is a function directly
  if (typeofreducer ! = ='function') throw new Error('Reducer must be an object')
  // Check whether enhancer is passed in
  if (typeofenhancer ! = ='undefined') {
    // Enhancer is passed to determine whether it is a function
    if (typeofenhancer ! = ='function')
      throw new Error('Enhancer must be a function')
    // Call the function for the function and pass in cerateStore as an argument
    // The function returns a function, which is called immediately
    // Pass reducer and preloadedState as parameters to the new function
    return enhancer(cerateStore)(reducer, preloadedState)
  }
  // Get the initial state
  let data = preloadedState
  / / subscriber
  let listeners = []
  // Get the state method
  function getState() {
    // Return to status directly
    return data
  }
  // instruction firing method
  function dispatch(action) {
    // Call the function to determine whether it is an object
    if(! isPlainObject(action))throw new Error('Parameter must be an object')
    // Check whether there is a type attribute
    if (typeof action.type === 'undefined') throw new Error('Need to pass in the type attribute')
    // Call argument returns the result
    data = reducer(data, action)
    // Traverse the subscriber to trigger the subscriber
    for (const listen of listeners) {
      listen()
    }
  }
  // Add subscriber method
  function subscribe(cb) {
    // cb is the callback function to be triggered by the subscriber
    listeners.push(cb)
  }
  // Returns an object composed of three methods
  return { getState, dispatch, subscribe }
}

// Determine whether the object is non-empty
function isPlainObject(obj) {
  // Exclude other cases from the array
  if (typeofobj ! = ='object' || obj === null) return false
  // Based on the top-level prototype object and its own prototype object
  let proto = obj
  while (Object.getPrototypeOf(proto) ! =null) {
    proto = Object.getPrototypeOf(proto)
  }
  return proto === Object.getPrototypeOf(obj)
}

// Middleware methods, using... Merges multiple parameters into an array
function applyMiddleware(. wares) {
  // As with Enhancer, you still need to create the basic store
  return function (cerateStore) {
    return function (reducer, preloadedState) {
      // Create store - basic
      let store = cerateStore(reducer, preloadedState)
      // Create a castrated version of store for import middleware
      let middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch,
      }
      // Executes all outermost middleware functions, returning an array of functions returned by the outermost middleware
      const chain = wares.map(ware= > ware(middlewareAPI))
      // Iterate through the array above, execute the second layer of middleware functions (destruct), pass the dispatch, and return
      constdispatch = compose(... chain)(store.dispatch)// Return to store and replace Dispatch
      return {
        ...store,
        dispatch,
      }
    }
  }
}

// Middleware layer 2 function execution
function compose() {
  // Takes an argument and converts it from a class array to an array
  const funcs = [...arguments]
  // Return the function, since store.dispatch is used, where dispatch is the next parameter in the middleware
  return function (dispatch) {
    // Execute the function backwards because the former middleware needs to use the third layer function returned by the latter middleware
    for (let i = funcs.length - 1; i >= 0; i--) {
      // Modify parameters to layer 3 functions of later middleware
      dispatch = funcs[i](dispatch)
    }
    // Returns the first middleware layer-2 function directly
    return dispatch
  }
}

// bindActionCreators handles the action
// Parameter 1: action collection
// Parameter 2: dispatch
function bindActionCreators(arr, diapatch) {
  // Create an empty object
  const actions = {}
  / / traverse the action
  for (let key in arr) {
    // Add attributes to the object, corresponding to action
    actions[key] = function () {
      // Notice the use of the action return value
      diapatch(arr[key]())
    }
  }
  // Returns the processed action directly
  return actions
}

// Merge the reducer method
function combineReducers(obj) {
  // Get all attribute names
  const keys = Object.keys(obj)
  Check whether all the imported reducer functions are functions. Otherwise, an error is reported
  for (let i = 0; i < keys.length; i++) {
    if (typeofobj[keys[i]] ! = ='function')
      throw new Error('Reducer must be a function')}// Return a function because the reducer at store creation must also be a function
  return function (state, action) {
    // Create a new state
    const newState = {}
    // Go through all incoming reducer, execute and pass it to the new state
    for (let i = 0; i < keys.length; i++) {
      newState[keys[i]] = obj[keys[i]](state[keys[i]], action)
    }
    // Directly export the new state as the reducer return value
    return newState
  }
}
Copy the code