浅读Redux源码

156 阅读5分钟
原文链接: mp.weixin.qq.com

之前整理了如何使用redux(见《React全家桶之Redux》),今天简单读一下redux源码, 一起来挖掘createStore的实现,不仅做到知其然,还要做到知其所以然。为了说明主要逻辑,文章仅列出其中的关键代码。

先看看createStore的返回值:

export default function createStore(reducer, initialState) {    ...    //返回 store 暴漏出的接口    return {        dispatch, //用于action的派发,改变store里面的state        subscribe, //订阅一个状态改变后要触发的监听函数         getState,  // 获取 store 里的 state        replaceReducer, //Redux热加载的时候可以替换 Reducer        [?observable]: observable //对象的私有属性,供内部使用    }}

每个属性的含义是:

dispatch: 用于action的派发,改变store里面的state。

subscribe: 注册listener,store里面state发生改变后,执行该listener。

getState: 读取store里面的state。

replaceReducer: 替换reducer,改变state修改的逻辑。

接下来挨个看看它们是怎么实现的。

getState:

function getState() {    return currentState}

整个项目的currentState是处于一个闭包之中,所以能一直存在。store.getState()读取store里面的state。

subscribe:

function subscribe(listener) { //判断 listener 不是一个函数 if (typeof listener !== 'function') {   //抛出一个异常 (listener 必须是一个函数)   throw new Error('Expected listener to be a function.') } //标记有订阅的 listener var isSubscribed = true //保存一份快照 ensureCanMutateNextListeners() //添加一个订阅函数 nextListeners.push(listener) //返回一个取消订阅的函数 return function unsubscribe() {   //判断没有订阅一个 listener   if (!isSubscribed) {     //调用 unsubscribe 方法的时候,直接 return     return   }   //标记现在没有一个订阅的 listener   isSubscribed = false   //保存一下订阅快照   ensureCanMutateNextListeners()   //找到当前的 listener   var index = nextListeners.indexOf(listener)   //移除当前的 listener   nextListeners.splice(index, 1) }}

subscribe接收一个listener,它的作用是给store添加监听函数,store里面state发生改变后,执行listener。nextListeners储存了整个监听函数列表。 subscribe的返回值是一个unsubscribe,是一个解绑函数,调用该解绑函数,会将已经添加的监听函数删除,该监听函数处于一个闭包之中,会一直存在,在解绑函数中能删除该监听函数。(由此可见redux源码设计的精巧,多处地方巧用闭包,精简了许多代码),这是常见的 发布订阅模式。

dispatch:

 function dispatch(action) {    //判断 action 不是普通对象。也就是说该对象由 Object 构造函数创建    if (!isPlainObject(action)) {      //抛出一个异常(actions 必须是一个普通对象. 或者用自定义的中间件来处理异步 actions)      throw new Error(        'Actions must be plain objects. ' +        'Use custom middleware for async actions.'      )    }    // 判断 action 对象的 type 属性等于 undefined     if (typeof action.type === 'undefined') {      //抛出一个异常      throw new Error(        'Actions may not have an undefined "type" property. ' +        'Have you misspelled a constant?'      )    }    //判断 dispahch 正在运行,Reducer在处理的时候又要执行 dispatch    if (isDispatching) {       //抛出一个异常(Reducer在处理的时候不能 dispatch action)      throw new Error('Reducers may not dispatch actions.')    }    try {      //标记 dispatch 正在运行      isDispatching = true      //执行当前 Reducer 函数返回新的 state      currentState = currentReducer(currentState, action)    } finally { // (try catch) 最终会被执行的地方      //标记 dispatch 没有在运行       isDispatching = false    }    //所有的的监听函数赋值给 listeners    var listeners = currentListeners = nextListeners    //遍历所有的监听函数    for (var i = 0; i < listeners.length; i++) {      // 执行每一个监听函数      listeners[i]()    }    //返回传入的 action 对象    return action  }

dispatch里,先做一些判断;执行reducer,并返回一个新的currentState;触发所有listeners。dispatch返回值是传入的action。

读了redux源码之后,为了更清晰深刻地理解redux,我们可以自己实现一个迷你redux,仅实现主要逻辑,不做其它严谨校验。

minRedux.js:

export function createStore(reducer){  //存储状态  let currentState = {};  //存储listener  let currentListerners = [];  //获取当前状态  function getState(){    return currentState;  }  //注册listener  function subscribe(listener){    currentListerners.push(listener);  }

  //调用reducer,得到一个新的currentState;  //每个listener都执行一下;  //返回值是一个action;

  function dispatch(action){    currentState=reducer(currentState,action);    currentListerners.forEach(fn=>fn())    return action;  }  //初始化store  dispatch({type:'@MIN-REDUX-INIT'});  return { getState , subscribe , dispatch}}
感谢阅读~

扫描二维码关注哦