Redux 源码解析

235 阅读2分钟

介绍

  • Redux:状态管理工具,他可以解决组件之间数据共享和数据通信。

特性

  • 基于单一store的数据管理(单一来源,集中管理数据更清晰)
  • 单向数据流,组件dispatch一个action,执行reducer,reducer里面根据action参数生成一个新的store,然后redux通知组件重新渲染(数据流清晰,对数据约束)
  • 数据不可变(它使用纯函数接收先前的 state 和 action,并返回新的 state,性能优化浅比较俩个对象是否改变,也便于调试)

源码实现

createStore的实现

  • 作用创建创建store

function (reducer,preloadedState,enhancer){
    if ( enhancer可以用 ) {// 中间件增强createStore
        return enhancer(createStore)(
          reducer,
          preloadedState 
        ) 
    }
    let currentReducer = reducer //当前store里面的store
    let currentState = preloadedState //当前stroe中的数据
    let currentListeners = [] //当前store中放置的监听函数
    let nextListeners = currentListeners //下一次dispath的监听函数
    
    
    // 获取state
    function getState(){
         return currentState
    }
    
    // 添加监听函数,每次dispatch的时候都会调用,返回一个取消监听的函数
    function subscribe(listener){
        nextListeners.push(listener);
        return function unsubscribe() {
          const index = nextListeners.indexOf(listener)
          nextListeners.splice(index, 1)
          currentListeners = null
        }
    }
    
    // 触发一个action,调用reducer得到新的state,执行所有store中的监听函数
    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
}

combineReducers的实现

  • 把子reducer合并成一个总的reducer,目的是为了把reducer拆分开来,对每个功能有一个不同的reducer。
    function combineReducers(reducers){
        // 遍历一遍reducers筛选出有用的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:检测每一个reducer接受一个初始action或一个未知的action时,能够返回效的值
        try {
            assertReducerShape(finalReducers)
        } catch (e) {
            shapeAssertionError = e
        }
         return function combination(state,action){
             let hasChanged = false // state是否改变标志
             const nextState = {} // 新的state
             for (let i = 0; i < finalReducerKeys.length; i++) {
                 const key = finalReducerKeys[i]
                 const reducer = finalReducers[key]
                 const previousStateForKey = state[key]// 得到该子reducer的旧的state
                 const nextStateForKey = reducer(previousStateForKey, action)// 得到该子reducer新的state
                 nextState[key] = nextStateForKey
                 hasChanged = hasChanged || nextStateForKey !== previousStateForKey
             
            } 
                hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length
                return hasChanged ? nextState : state
    }
      

Redux 中间件

 const store = createStore(reducer,states, applyMiddleware(logger))
 // createStore中的当enhancer可以用
 if ( enhancer可以用 ) {// 中间件增强createStore
        return enhancer(createStore)(
          reducer,
          preloadedState 
        ) 
    }
  • 在createStore中入参enhancer是通过applyMiddlewarec传入中间健返回的

applyMiddleware的实现

function applyMiddleware(...middlewares) {
  return (createStore) =>
   (
      reducer,
      preloadedState,
    ) => {
      // 根据传进来的createStore,reducer, preloadedState生成一个store
      const store = createStore(reducer, preloadedState)
      // 在dispatch改造完成前调用则会抛出错误
      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)
      }
      // 将store中的state和dispatch传给中间件
      const chain = middlewares.map(middleware => middleware(middlewareAPI))
      // compose多个函数组合成一个函数,在compose源码中
      // funcs.reduce((a, b) => (...args) => a(b(...args)))
      // 返回改造后的dispatch
      dispatch = compose(...chain)(store.dispatch)
      return {
        ...store,
        dispatch
      }
    }
}
  • 中间健的基本格式是
   ({dispatch,state})=>next=>action=>{
        //中间件的具体代码
        next(action)
   }
   // 展开箭头函数
   // 接受store中的dispath和state
   fcuntion (dispatch,state){
        // 接受上一个改造后的dispatch,第一个则为store.dispatch
        return function (next){
            // 改造后的dispatch方法
            return function (action){
                 next(action)
             }
        }
   }

redux-logger和redux-thunk

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


// redux-thunk有效代码
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}