美文网首页
Redux源码解读之 createStore

Redux源码解读之 createStore

作者: 太上云初 | 来源:发表于2019-03-25 14:35 被阅读0次

介绍

createStore 用来创建应用的状态树,提供了状态树的访问和管理方式,用于维护整个应用的数据状态和页面渲染。

本文只展示并解释核心代码。


store 对象

createStore 接受 reducer、 preloadedState、enhancer 三个参数, 返回 store 对象。通过 store 暴露的 API 进行 store 状态树的管理。

//主要的API如下

store = {
    getState,
    subscribe,
    dispatch,
    replaceReducer,
}

ensureCanMutateNextListeners

在 createStore 函数中有一个有意思的函数 ensureCanMutateNextListeners,字面上翻译是确保能够改变下一次的事件监听器数组。

实质上,这个函数保证了 subscribe 和 unsubscribe 的执行不会影响订阅事件的循环执行。我们看一下这个函数的实现

let currentListeners = []               //储存用户的订阅事件
let nextListeners = currentListeners    //nextListeners 与 currentListeners 保持同引用地址 
function ensureCanMutateNextListeners(){
    if(nextListeners === currentListeners){
        nextListeners = currentListeners.slice();
    }
}

这个函数主要是针对 currentListeners 和 nextListeners 两个数组,在初始化的时候二者保持相同的引用地址。在 执行 subscribe 和 unsubscribe 时,执行 ensureCanMutateNextListeners 通过比较二者的引用地址,如果相同则生成一个新的引用地址,但是两者的内容是相同。在执行 dipatch 时,将二者的应用地址指向同一个引用地址。

在 dispatch 函数中,我们通过循环遍历 nextListeners 所引用的订阅事件数组,进而执行每一个订阅事件。如果没有 ensureCanMutateNextListeners 函数,采取同一个引用地址,那么在执行 subscrib 和 unsubscrib 函数时,会对相同的订阅事件数组进行改变,从而影响到订阅事件的循环执行。

具体含义如图所示:

image

getState

返回整个状态树, 这个方法并没有什么有意思的地方,也非常简单明了。

function getState(){
    if(isDispatching){
        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;
}

subscribe

订阅 store 的状态变化,可以进行适时地渲染

subscrib 将所有订阅事件函数储存起来,返回一个函数,用于取消该订阅事件函数。利用闭包,保持对 listener 的引用,从而获取 listener 在数组中位置,进行删除操作。

function subscribe(listener){
    let isSubscribed = true;
    ensureCanMutateNextListeners();
    nextListeners.push(listener);
    return function unsubscribe(){
        if(!isSubscribed){
            return;
        }
        if(!isDispatching){
            throw new Error(
              'You may not unsubscribe from a store listener while the reducer is executing. ' +
                'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
            )
        }
        isSubscribed = false;
        ensureCanMutateNextListeners();
        const index = nextListeners.indexOf(listener);
        nextListeners.splice(index, 1);
    }
}

dispatch

派发 action, 用于改变更新状态树。用于改变状态的 action 必须是纯对象,即是字面量声明 或者 new Object 创建的对象。

function dispatch(action){
    if(!isPlainObject(action)){
        throw new Error(
            'Actions must be plain objects. ' +
              'Use custom middleware for async actions.'
          )
    }
    if(isDispatching){
        throw new Error('Reducers may not dispatch actions.')     
    }
    
    try {
        isDispatching = true;
        currentState = currentReducer(currentState, action);
    } finally {
        isDispatching = false
    }
    
    let listeners = (currentListeners = nextListeners);
    for(let i = 0; i < listeners.length; i++){
        const listener = listeners[i];
        listener();
    }
    return action;
}

相关文章

网友评论

      本文标题:Redux源码解读之 createStore

      本文链接:https://www.haomeiwen.com/subject/aenvvqtx.html