redux系列(二)--- redux源码解读

redux系列(二)--- redux源码解读

redux虽然强大,但是它的源码确实很简单


####createStore createStore返回的是一个对象,并且这个对象有如下成员函数dispatch,subscribe,getState,replaceReducerobservable

下面看它的核心源码(已经去掉一些对参数的判断):

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.')
    }
    return enhancer(createStore)(reducer, preloadedState)
  }

这一段是通过传入的参数类型来做判断的如果只传入两个参数,并且第二个参数是函数而不是对象的时候,此时直接进行替换赋值。并且当检测到第三个参数enhancer不为空并且符合规范的时候,直接执行 enhancer(createStore)(reducer, preloadedState) 这一段其实是为之后的中间件进行服务的 然后是定义了一系列变量:currentState,currentListener,nextListener等。然后就开始依次实现store暴露的几个函数 getState函数很简单,只是返回currentState而已

function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }
    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)
    }
  }

subscribe函数的实现是通过nextListener数组来实现对当前listeners来进行增删,之所有需要一个currentListener又需要一个nextListener,是因为如果直接在currentListener上进行修改,会导致由于数组是复杂类型,一旦进行更改会使整个数组发生改变。

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

上面是dispatch的核心源码,去掉了一些类型检测,这个函数主要是通过设置了一个isDispatching标志位,来判断传入的action是否已经被监听过,否则则直接调用reducer函数,并且将listener数组都执行一遍 再继续往下看,replaceReducer也很简单,略过

####combineReducers 这部分的代码很长,但是大部分都是在对参数做一些校验处理,核心源码是下面几行

const finalReducerKeys = Object.keys(finalReducers)
...
   let hasChanged = false
    const nextState = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    return hasChanged ? nextState : state
  }

主要的过程如下:

  • 检验传递进来的参数reducer是否是合法的,然后将合法的reducer放进finalReducer中,并获取对应的key
  • 通过一个for循环,实现对应的reducer获取对应key值的state
  • 返回改变过的state 通过上面的实现,那么下面两种写法也是等价的
第一种:
function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}

第二种:
const todoApp = combineReducers({
  visibilityFilter,
  todos
})

####bindActionCreators 这个函数的作用,主要是弱化了store.dispatch的作用,直接在bindActionCreators中进行封装了,源码如下:

function bindActionCreator(actionCreator, dispatch) {
  return (...args) => dispatch(actionCreator(...args))
}
export default function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }
  const keys = Object.keys(actionCreators)
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  return boundActionCreators
  }
  • 首先是判断传入的actionCreators这个参数是function还是一系列function数组
  • 如果是function,那就直接执行bindActionCreator,可以看到bindActionCreator中实现了dispatch的功能
  • 如果传入的是数组,则通过for循环对每一个进行上一步的操作

作用:自动把action创建函数绑定到dispatch中,省略通过store.dispatch()进行手动dispatch

####applyMiddleware 这是唯一一个很绕的API,虽然代码很简洁,下面对它进行分析:

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}
  • 首先通过调用createStore来生成一个store,并且获取到dispatch,定义了一个空数组chain,
  • storedispatch作为参数传入middleware中,先来看看中间件的统一格式:
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
    return next(action);
  };
}

上面这个格式是采用了ES6的语法格式,解析应该是下面这样:

    return function (next) {
        return function (action) {
            return next(action);
        }
    }
}
  • middleware经过处理后pushchain数组
  • composechain数组进行处理 先来看看compose的实现源码:
export default function compose(...funcs) {
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

compose底层调用的是Array.prototype.reduceRight 举例: Dispatch = compose([fn1,fn2,fn3])(store.dispatch)会被解析成如下所示: dispatch = f1(f2(f3(store.dispatch)),也就是f3的返回值作为f2的参数,f2返回值作为f1的参数

  • 通过compose处理后返回return next(action) 其实是如下:
function(action){
      if (typeof action === 'function') {
           return action(dispatch, getState, extraArgument);
      }
      return next(action);
 }

这个也是包装后的store.dispatch,与原先的store.dispatch不同,通过这种方式一直进行传递

为什么middlewareApi中要使用这一行dispatch: (action) => dispatch(action),而不是直接dispatch:dispatch 因为store.dispatch是一直在改变的,并且需要获取到最新的store.dispatch,这一句正是实现这个功能,每次都可以获取最新的,而不是最先的那个store.dispatch

至此,完结

转载于:https://my.oschina.net/sunshinewyf/blog/828551

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值