createStore

Generally speaking, I look at the source code of a library, looking first at the parameters of the corresponding method, then at the corresponding return, and then at the implementation of the code.

The createStore method returns an object that exposes five methods, four of which are commonly used:

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
Copy the code

Looking at the beginning of the source code, we see that createStore can pass in two triadic parameters:

export default function createStore(reducer, preloadedState, enhancer) 
Copy the code

The first reducer parameter must be passed and must be a function, or Redux returns a reducer

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

If the second argument, preloadedState, is passed and not a function, then preloadedState is stored in the internal variable currentState, which is the default State we gave State

If preloadedState is a function, assign preloadedState to enhancer

  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if(typeof enhancer ! = ='undefined') {
    if(typeof enhancer ! = ='function') {
      throw new Error('Expected the enhancer to be a function.'} // Run enhancer. Enhancer is a group of middlewarereturn enhancer(createStore)(reducer, preloadedState)
  }

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

Three important variables are saved in this method:

let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
Copy the code
  1. CurrentReducer saves all Reducer files
  2. CurrentState is where all the state data is stored and is the only object where Redux manipulates the data
  3. CurrentListeners save listeners to Redux State subscriptions

Now that we know the three main internal variables Redux can control, we will learn how to manipulate them based on the five methods revealed by createStore

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
Copy the code

Dispatch (remove verification code)

  function dispatch(action) {
      try {
      isDispatching = true// Call Reduce to process the action, passing in the original state each time. Returns the updated States currentState = currentReducer(currentState, Action)} finally {isDispatching =falseConst listeners = (currentListeners = nextListeners)for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }
Copy the code

We first need to pass an action parameter to tell the action Object that we need to do. The action can only be an Object and must contain the Type field

    if(! isPlainObject(action)) { throw new Error('Actions must be plain objects. ' +
        'Use custom middleware for async actions.')}if (typeof action.type === 'undefined') {// Must contain **Type** throw new Error('Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant? ')}Copy the code

We call the internal variable currentReducer to handle the corresponding action initiated

currentState = currentReducer(currentState, action)
Copy the code

CurrentReducer is a function that takes two arguments: currentState and Action.

The value returned by currentReducer is assigned to currentState, as is known from the analysis of the argument passed in to createStore, PreloadedState can only be given to Object, so currentReducer function returns to Object.

From this line of code we can conclude:

Reducer is a function that processes currentState based on actions and returns a new currentState function

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

As we can see from the above code, when updating state, we need to iterate over all the listeners to let them know the information of state change

The subscribe (subscription)

Subscribe is a message subscription

  function subscribe(listener) {
    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if(! isSubscribed) {return
      }   
      isSubscribed = false
      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
Copy the code

Very simple code, the listener is passed in as a subscriber method,

 nextListeners.push(listener)
Copy the code

Store the listener in an array of internal variables. Returns an unsubscribe method that unsubscribes

Listeners are unsubscribed whenever they are removed from the arrayCopy the code

GetState (getState)

  function getState() {
    return currentState
  }
Copy the code

Very simple, just return the internal variable currentState

ReplaceReducer replacement (reducer)

 function replaceReducer(nextReducer) {
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }

Copy the code

Replace the current reducer.

conclusion

  1. First we need to create a store by calling the createStore method
 let store = createStore(reducer, preloadedState)
Copy the code

Reducer is a function and two parameters must be passed, the first being state and the second an action

  1. Trigger store.dispatch(Action) with related events to change the state

This action must have a type attribute

  1. Store. Subscribe (listener)
  2. Get the latest state(store.getState()) in the listener and proceed accordingly

Redux examples