introduce

  • Redux: a state management tool that addresses data sharing and communication between components.

features

  • Single Store-based data management (single source, centralized management of data is clearer)
  • Unidirectional data flow, component dispatch an action, reducer is implemented, a new store is generated according to action parameters, and redux informs the component to re-render (data flow is clear and data constraints are limited)
  • Data immutable (it uses pure functions to receive the previous state and action and return the new state, performance optimization shallow comparison of whether the two objects have changed, also easy to debug)

The source code to achieve

The realization of the createStore

  • Create Creates a store

function (reducer,preloadedState,enhancer){
    if(enhancer can be used) {Middleware enhances createStore
        return enhancer(createStore)(
          reducer,
          preloadedState 
        ) 
    }
    let currentReducer = reducer // Store within the current store
    let currentState = preloadedState // Data in the current stroe
    let currentListeners = [] // The listener placed in the current store
    let nextListeners = currentListeners // Next dispath listener
    
    
    / / for the state
    function getState(){
         return currentState
    }
    
    // Add a listener function, which is called every time at dispatch and returns an unlistener function
    function subscribe(listener){
        nextListeners.push(listener);
        return function unsubscribe() {
          const index = nextListeners.indexOf(listener)
          nextListeners.splice(index, 1)
          currentListeners = null}}// Trigger an action, call Reducer to get the new state, and execute the listening functions in all stores
    function dispatch(action: A) {
         currentState = currentReducer(currentState, action)
         const listeners = (currentListeners = nextListeners)
         for (let i = 0; i < listeners.length; i++) {
          const listener = listeners[i]
          listener()
        }
        return action
     }
    
    const store = {
        dispatch,
        subscribe,
        getState,
        replaceReducer,
        [$$observable]: observable
      } 
    return store
}
Copy the code

The realization of the combineReducers

  • Merge the reducer into a total reducer. The purpose is to split the reducer and have a different reducer for each function.
    function combineReducers(reducers){
        // Go through the reducers and select the useful reducer
        const reducerKeys = Object.keys(reducers)
        const finalReducers = {}
        for (let i = 0; i < reducerKeys.length; i++) {
        const key = reducerKeys[i]
        if (typeof reducers[key] === 'function') {
          finalReducers[key] = reducers[key]
        }
        
        const finalReducerKeys = Object.keys(finalReducers)
        AssertReducerShape: Checks that each reducer can return a valid value if it accepts an initial action or an unknown action
        try {
            assertReducerShape(finalReducers)
        } catch (e) {
            shapeAssertionError = e
        }
         return function combination(state,action){
             let hasChanged = false // state whether to change the flag
             const nextState = {} / / the new state
             for (let i = 0; i < finalReducerKeys.length; i++) {
                 const key = finalReducerKeys[i]
                 const reducer = finalReducers[key]
                 const previousStateForKey = state[key]// Get the old state from the reducer
                 const nextStateForKey = reducer(previousStateForKey, action)// Get the new state of the reducernextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey ! == previousStateForKey } hasChanged = hasChanged || finalReducerKeys.length ! = =Object.keys(state).length
                return hasChanged ? nextState : state
    }
      
Copy the code

Redux middleware

 const store = createStore(reducer,states, applyMiddleware(logger))
 // When enhancer can be used in createStore
 if(enhancer can be used) {Middleware enhances createStore
        return enhancer(createStore)(
          reducer,
          preloadedState 
        ) 
    }
Copy the code
  • The entry enhancer in createStore is returned by applyMiddlewarec passing in the intermediate key

The realization of the applyMiddleware

function applyMiddleware(. middlewares) {
  return (createStore) = >
   (reducer, preloadedState,) = > {
      Create a store based on the incoming createStore, Reducer, preloadedState
      const store = createStore(reducer, preloadedState)
      // An error is thrown when called before the dispatch transformation is complete
      let dispatch: Dispatch = () = > {
        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: (action, ... args) = >dispatch(action, ... args) }// Pass state and dispatch from store to middleware
      const chain = middlewares.map(middleware= > middleware(middlewareAPI))
      // compose compose multiple functions into one function, in the compose source code
      // funcs.reduce((a, b) => (... args) => a(b(... args)))
      // Return to the modified dispatchdispatch = compose(... chain)(store.dispatch)return {
        ...store,
        dispatch
      }
    }
}
Copy the code
  • The basic format of intermediate keys is
   ({dispatch,state})=>next= >action= >{
        // Middleware specific code
        next(action)
   }
   // Expand the arrow function
   // Accept dispath and state in store
   fcuntion (dispatch,state){
        // Accept the last modified dispatch, the first one is store.dispatch
        return function (next){
            // The modified dispatch method
            return function (action){
                 next(action)
             }
        }
   }
Copy the code

Story – logger and story – thunk

// redux-logger valid code
const logger = store= > next= > action= > {
    console.log('dispatch:',action);
    let returnedValue = next(action);
    console.log('finish:',action);
    return returnedValue
}


// redux-thunk valid code
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) = > next= > action= > {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}
Copy the code