redux api解读

查看源码后的记录(最近会整理下电脑里之前的一些笔记,发到csdn)

createStore

createStore会初始化store里的state,并且添加一系列的api:

  • dispatch
  • subscribe
  • getState
  • replaceReducer
  • [$$observable]: observable

store的state只是createStore里的一个普通变量,store的初始化状态可以通过createStore的第二个参数指定,如果没有指定,也可以通过reducer的默认参数指定,因为调用createStore的时候会dispatch一个用于init的actionType,这个actionType是随机的,所以会设置上给reducer的state默认参数。第三个参数是一个增强器,增加store的功能,redux自带的增强器只有applyMiddleware函数,从createStore的部分源码可以看到增强器的调用,同时会直接返回增强器的结果:

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

    return enhancer(createStore)(reducer, preloadedState)
  }

增强器会接收createStore函数作为参数。

dispatch

每次触发action会调用所有reducer,同时会在之后依次调用subscribe订阅的监听器。

subscribe

subscribe函数将注册的监听器添加到nextListeners队列,nextListenerscurrentListeners的浅拷贝对象,然后返回一个unsubscribe函数,unsubscribe会将监听函数从nextListeners里去除。nextListeners作为dispatch过程中的currentListeners一个临时列表,防止在dispatch过程中调用subscribe和unsubscribe函数造成bug。

getState

获取store里的state:

function getState() {
    if (isDispatching) { // 如果正在进行dispatch过程会报错
      throw new Error(
        'You may not call store.getState() while the reducer is executing. ' +
          'The reducer has already received the state as an argument. ' +
          'Pass it down from the top reducer instead of reading it from the store.'
      )
    }

    return currentState // 该变量存储了store里的所有state
  }

replaceReducer

替换reducer并重置store里的state。

combineReducers

接收多个reducer函数(reducers对象),除了作一些校验外,就返回一个函数,该函数将接收到的stateaction依次传递给所有的reducer,每个reducer执行后返回一个子state,最后以键值对的方式组合成最后store的完整状态,键就是reducers对象的键,值即为对应reducer返回的子state。

bindActionCreators

接收由多个actionCreator组成的一个对象和dispatch作为参数:

bindActionCreators(actionCreators, dispatch)

// actionCreators案例:
{
    creatorA: () => ({ type: 'xx' })
}

// 返回案例
{
    creatorA: function() {
        dispatch(creatorA.apply(this, arguments)
    }
}

applyMiddleware

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
      // 防止在构建中间件的时候,调用dispatch
    }

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

可以看到applyMiddleware函数会返回一个闭包函数,也就是一个enhaner,这个闭包函数返回的对象表明,使用中间件后,除dispatch函数外的其他store属性都不变化,所以中间件的功能就是对原本的dispatch函数进行包裹,至于新的dispatch函数功能得看compose函数如何处理多个中间件:

// compose函数源码,compose(f, g, h)的结果:(...args) => f(g(h(...args)))
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

这么看的话,可能会绕进去,写个简单例子分析。
首先构造三个简单的中间件,一个redux中间件的结构我们可以看看redux-thunk的源码:

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') { 
      // 异步action是一个函数,收到三个参数
      // 第三个参数可以是一些我们自定义的api
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

可以得出一个redux中间件的大致结构应该是这样(且我们应该了解中间件是拦截了action到reducer这个过程):

const middleware = ({
    getState,
    dispatch
}) => next => action => {
    // 处理逻辑
    // 处理逻辑完成后,调用next,也就是进入到下一个中间件
    next(action)
}

三个简单的中间件:

// 中间件f
const middlewareF = ({
    getState,
    dispatch
}) => nextF => action => {
    /*
     * 处理中间件f的逻辑
     */
    nextF(action)
}
// 中间件g
const middlewareG = ({
    getState,
    dispatch
}) => nextG => action => {
    /*
     * 处理中间件g的逻辑
     */
    nextG(action)
}
// 中间件h
const middlewareH = ({
    getState,
    dispatch
}) => nextH => action => {
    /*
     * 处理中间件h的逻辑
     */
    nextH(action)
}

使用applyMiddleware处理三个中间件:

applyMiddleware(
    middlewareF,
    middlewareG,
    middlewareH
)

当函数走到调用compose函数处时,chain变量应该是:

const f = nextF => action => {
    /*
     * 处理中间件f的逻辑
     */
    nextF(action)
}
const g = nextG => action => {
    /*
     * 处理中间件g的逻辑
     */
    nextG(action)
}
const h = nextH => action => {
    /*
     * 处理中间件h的逻辑
     */
    nextH(action)
}
const chain = [
    f,
    g,
    h
]

compose(...chain)包装后返回:

(...args) => f(g(h(...args)))

再看compose(...chain)(dispatch)的结果:

f(g(h(dispatch))) // 返回结果

// 一步步来分析,先执行h(dispatch),将h(dispatch)的结果赋值给h1
const h1 = action => {
    /*
     * 处理中间件h的逻辑
     */
    dispatch(action)
}
// g(h(dispatch))就变成了g(h1),返回结果赋值给g1
const g1 = action => {
    /*
     * 处理中间件g的逻辑
     */
    h1(action)
}
// 最后时f(g1),也就是f(g(h(dispatch)))解析后的结果,同是也是新的dispatch函数的结果,这样看的会清晰一点
const f1 = action => {
    /*
     * 处理中间件f的逻辑
     */
    g1(action)
}

分析完毕后,可以看到新的dispatch函数执行,会按顺序处理各个中间件的逻辑,并且在最后一个中间件使用原来的dispatch函数触发action。

compose

就是对一组功能的组合,且是从右到左。

总结

阅读redux的源码后,会发现很大一部分代码都是在对参数作校验,抛出错误等(js本身没有类型约束),核心代码其实很简洁,阅读很舒服

你可能感兴趣的:(【源码解读】,redux,源码)