Redux source code analysis series (3) — create store

Time:2021-5-4

The source code address of the createstore is:https://github.com/reactjs/re…

Now I’ll analyze it~
This method is reserved for Redux and is used to initialize the state of the reducer

export const ActionTypes = {
  INIT: '@@redux/INIT'
}

As mentioned earlier, the function of createstore is to create a store to manage the state of the app. The only way to change the state is to dispatch an action and finally return an object.

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

However, replacereducer and [$$observable]: are not commonly used ~, so only the first three interfaces are analyzed here.

In an app, there can only be one store. If you want to specify different states corresponding to different actions, you can use combine reducers to merge different reducers.

Parameters:

  • Reducer (function): it calculates the next state and returns it by passing in the current state and action.

  • preloadedState(any):initial state

  • Enhancer (function): enhance the function of the store and let it have third-party functions, such as applymiddleware ()

export default function createStore(reducer, preloadedState, enhancer) {
//The first paragraph says that when the second parameter is passed directly to function instead of preloadedstate, the function will be regarded as enhancer
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }
  //When the third parameter is passed but not function, an error will be reported
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    //The key is here. In the previous article, I introduced the significance of doing this,
    //In fact, creating store is done in applymiddleware, which transfers the pot.
    return enhancer(createStore)(reducer, preloadedState)
  }

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

  let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false
   ....
}

The above is the first part. After verifying the correctness of the parameters, we can finally get down to business.
The createstore will eventually return an object,

{
 dispatch,
 subscribe,
 getState
}

Next, let’s see what’s done inside:

getState

Getstate is used to return the state of the current state. There is nothing to say~

function getState() {
   return currentState
}

subscribe

Function: add the listener function, which will be called every time the dispatch action.
Parameter: listener (function): the function that will be called in each dispatch action
Return: returns a function to remove the listener

//The purpose of this function is to copy a copy if nextlisteners and nextlisteners point to the same stack, so that the nextlisteners will not be changed to currentlisteners
function ensureCanMutateNextListeners() {
    if (nextListeners === nextListeners) {
      nextListeners = currentListeners.slice()
    }
}

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

    let isSubscribed = true

    ensureCanMutateNextListeners()
    //Put the listening function directly into nextlisteners
    nextListeners.push(listener)

    return function unsubscribe() {
    //If it has been removed, return directly
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      //If not, find the location first and remove it through splice
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

When using it, you can:

const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

unsubscribe()

dispatch

As an important function, dispatch actually triggers the change of state.
Parameter: action (object), which is an object describing what happened, in which type is a required attribute.
Return: the incoming object

function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }
    //
    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }
    //To prevent multiple dispatch requests from changing the status at the same time, the next dispatch must be completed after the previous dispatch
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }
   
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    //When dispatching, assign nextlisteners back to currentlisteners,
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

After completing the above series, you need to initialize the state of appstate. When the init action is dispatched, each reducer will return to its initial state

dispatch({ type: ActionTypes.INIT })

reference material:
https://github.com/reactjs/re…

Recommended Today

Large scale distributed storage system: Principle Analysis and architecture practice.pdf

Focus on “Java back end technology stack” Reply to “interview” for full interview information Distributed storage system, which stores data in multiple independent devices. Traditional network storage system uses centralized storage server to store all data. Storage server becomes the bottleneck of system performance and the focus of reliability and security, which can not meet […]