
之前整理了如何使用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}}
感谢阅读~
扫描二维码关注哦