介绍
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 函数时,会对相同的订阅事件数组进行改变,从而影响到订阅事件的循环执行。
具体含义如图所示:

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;
}
网友评论