Redux Source Interpretation (5) createStore

Here's the last function, CreateStore. Let's start with a basic usage.

const store = createStore(reducers, state, enhance);
This enhance r is apply Middleware (middleware), as you can see. Last article.

Here is the source code. First of all, the logic of the first execution of so many code is very simple. Most of the code defines a function to wait for the call. The real thing is to call a default dispatch method and initialize the current state.

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { //The first step shows that the second parameter can be passed, and if not undefined, the enhancer can be transited to the third parameter.
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {   //enhancer must be a function
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)  //If you pass enhancer, you pass createStore as a parameter. As I said in my previous article, the third parameter can be passed without, because it will not be received here at all! CreateStore will be executed and returned in applymiddleware.
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  let currentReducer = reducer
  let currentState = preloadedState   //Current state
  let currentListeners = []     //Current listeners
  let nextListeners = currentListeners
  let isDispatching = false   //Is it being distributed?

  function ensureCanMutateNextListeners() {    //I can't say why I copied an array shallowly here. If you know it, please help me to answer it.
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()  //Just a copy.
    }
  }

  function getState() {  //Return to the current state
    return currentState
  }

  
  function subscribe(listener) {
    if (typeof listener !== 'function') {  //If the listener is a function
      throw new Error('Expected listener to be a function.')
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()  
    nextListeners.push(listener)

    return function unsubscribe() {  //Returns a function to deactivate the listener
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)    //Remove from listeners
    }
  }

  function dispatch(action) {
    if (!isPlainObject(action)) {   //action must be an object {type:'XXX'}
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') {  //Objects must have type attributes (uniquely identifying an action that cannot be repeated)
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }

    if (isDispatching) {   //Two dispatch es cannot be executed simultaneously
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)    //Whether or not the current state is first passed in, the default value is returned based on the first reducer
      //For example, the first execution of createStore will pass in a type that hardly exists in the case of reducer, so that the default value of the first entry of reducer can be returned.
    } finally {
      isDispatching = false   //Open the dispatch entrance
    }

    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()   //Execute the listener once
    }

    return action
  }

  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    currentReducer = nextReducer  //Replace the current reducer and execute the default dispatch to return the default value.
    dispatch({ type: ActionTypes.INIT })
  }

//Since a regular reducer returns a default value, this step (ActionTypes are rarely defined) is performed to return the default value of reducer.
  dispatch({ type: ActionTypes.INIT })

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer
  }
}

Maybe that's the source code. From the last article, we can find that this middleware can be composed, that is to say, it can be combined to achieve the purpose of strengthening dispatch. So what can we do with compose, an applymiddleware?

Promote:

We found that in the createStore we did not say applymiddleware directly, but used the term enhancer, the enhancer.

So I think applymiddleware is actually an enhancer, and that's definitely not the only one. For example:

const store = createStore(combineReducers({ routering: routerReducer }),
    {},
    composeEnhancers(  //This function is also referenced in a class library.
        applyMiddleware(myTestMidware_delay, ...middleware,myTestMidware),
        myEhancer
    )
);
Or the compose routine. The parameter I pass is the createStore function, which returns a createStore function, and then executes the last incoming createStore in the next function. That's what we need to do. The enhancement here is the createStore function.

const myEhancer = (createstore)=> (reducer, preloadedState) => {
    const store = createstore(reducer, preloadedState);   //Receive the returned store and continue to enhance.
    const dispatch = (action)=>{
        console.log('I am a Enhancer,action For:',action);
        return store.dispatch(action);
    }
    return {...store,dispatch};
}
Because createStore is more than just an executing operation, the return here cannot be omitted. Every time it returns, it is its own enhanced store.

Enhancer can also enhance dispatch, so it can be achieved through middleware, which can be achieved through enhancer.

Finally, who knows what the ensureCanMutateNextListeners are for, leave a message, thx.




Posted by jschofield on Sat, 18 May 2019 16:12:41 -0700