Redux源码简析

557 阅读2分钟

Redux核心概念

  • 单一 store ,只能挺过getState()获取状态,不能直接修改
  • 只能通过触发 action 修改状态
  • 使用纯函数 reducers 描述action如何改变state

整个redux的实现就是围绕上面的这三点进行实现的,整个源码量不大,理解了核心概念后去看源码会发现源码的结构逻辑非常清晰,代码中的注释也非常全面,本篇文章会按照如何实现核心概念的方式去阅读源码。(默认你已经会使用redux了)

Reducer

我们首先来看 reducer 在 redux中的使用来更加深入理解reducer的作用

currentState = currentReducer(currentState, action)

这是 redux 中唯一使用到 reducer 的地方,在dispatch函数中,将旧的state和dispatch的action传入得到新的state,这和redux对于reducer的描述是一模一样的,所以我们在编写 reducer 函数的时候一定要严格遵循redux的规范写成纯函数,这样可以保证你的state变化可以被方便的追踪到。

Action

我们所有的action都要通过 dispatch 所以我们直接来看dispatch的实现,比较有意思的就是redux内其实是有一把同步锁 isDispatching ,这样的做法避免掉了很多处理并发的逻辑,例如并发会带来读脏数据的风险,在看源码之前是根本不知道redux有这样的一个设计的。

function dispatch(action) {
    // 省略了一些错误aciton的检测代码 总结下来就是aciton一定是对象并且有type属性
    // isDispatching 类似于同步锁,保证每次修改state的原子性
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }
    try {
      isDispatching = true
      //获取新的state
      currentState = currentReducer(currentState, action)
    } finally {
      //开锁
      isDispatching = false
    }
    //通知订阅的函数
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

Store

redux最重要的部分就是createStore,他将存储state,把reducer和action组合在一起。

// 接收 reducer 初始state applyMiddleware添加中间件后返回的函数
export default function createStore(reducer, preloadedState, enhancer) {
  // 解决我们不传 preloadedState 第二个参数是 enhancer 的情况
  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.')
    }
    // 在 applyMiddleware 中enhancer做的事情就是添加中间件增强dispatch的能力
    return enhancer(createStore)(reducer, preloadedState)
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }
  //store中的转态
  let currentReducer = reducer
  //我们的state树
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false
  ...
  //返回 store对象以及api
  return {
    //触发aciton使用
    dispatch,
    //添加state改变的回调使用
    subscribe,
    //获取 state
    getState,
    //替换 reducer
    replaceReducer,
    [$$observable]: observable
  }

总结

整个redux源码看下来大概只需要一个小时,但是整体的收获还是非常大的,我们可以看到redux作者是从核心概念入手,一点点将其转化为工具的。