create报错不是函数_redux源码分析之一:createStore.js

createStore.js是redux的核心文件,暴露了一个函数createStore,函数执行后返回一个对象,该对象包含了4个关键的方法:dispatch, subscribe, getState, replaceReducer,代码如下。

export default function createStore(reducer, preloadedState, enhancer) {

//中间代码略

return {

dispatch,

subscribe,

getState,

replaceReducer,

[$$observable]: observable

}

}

一、createStore函数的参数:

reducer:reducer是一个函数,该函数会返回一个全新的state,而state则保存了所有的数据

preloadedState:初始state

enhancer:这个参数特别有意思,如果该enhancer参数存在的话,会将当前的createStore函数作为参数传入enhancer函数,并且,enhancer执行之后得到一个新函数,该新函数其实就是一个加强版的createStore函数,新的函数会把之前的reducer和preloadeState作为参数传入并执行。这个enhancer参数为redux中间件提供了入口。

二、参数检查代码及异常处理:

//如果preloadedState没有传,但是enhancer参数传了,重置一下变量

if (typeof preloadedState === 'function' && typeof enhancer === 'undefined')

{

enhancer = preloadedState

preloadedState = undefined

}

//如果enhancer传了,但是不是函数,则报错提示,否则执行enhancer函数,

//并继续执行enhancer函数返回的加强版的createStore函数,

//参数reducer以及preloadeState和原createStore函数保持一致

if (typeof enhancer !== 'undefined') {

if (typeof enhancer !== 'function') {

throw new Error('Expected the enhancer to be a function.')

}

return enhancer(createStore)(reducer, preloadedState)

}

//如果reducer不是函数,则报错

if (typeof reducer !== 'function') {

throw new Error('Expected the reducer to be a function.')

}

三、定义的几个局部变量:

let currentReducer = reducer //保存了当前的reducer函数,该reducer函数可以被动态替换掉

let currentState = preloadedState //保存了当前的state数据

let currentListeners = [] //保存了当前注册的函数列表

let nextListeners = currentListeners

let isDispatching = false //是否正在dispatch一个action

最关键的是currentState变量,调用createStore之后,currentState变量保存了当前状态的所有数据

四、定义了几个函数:

//确保nextListeners和currentListeners不是同一个引用

function ensureCanMutateNextListeners() {

if (nextListeners === currentListeners) {

//如果是同一个引用,则浅拷贝currentListeners到nextListeners

nextListeners = currentListeners.slice()

}

}

//getState函数,返回局部变量currentState,以获取当前状态

function getState() {

return currentState

}

//注册一个函数,将注册函数放入局部变量nextListeners数组里面

//注册函数的返回值是一个注销函数,注销函数执行可以将刚刚添加进nextListeners的listener函数又删除掉。这里很有意思,外部必须在调用subscribe执行现场保存好unsubscribe函数,否则将无法注销一个函数

function subscribe(listener) {

//如果listener不是函数,直接报错

if (typeof listener !== 'function') {

throw new Error('Expected listener to be a function.')

}

let isSubscribed = true

//确保nextListeners不是currentListeners,以保证修改的是nextListeners,而不是currentListeners

ensureCanMutateNextListeners()

//将监听函数放入监听函数列表尾部

nextListeners.push(listener)

//返回一个函数,该函数可以从监听函数列表中删除刚刚注册的监听函数

return function unsubscribe() {

if (!isSubscribed) {

return

}

isSubscribed = false

ensureCanMutateNextListeners()

const index = nextListeners.indexOf(listener)

nextListeners.splice(index, 1)

}

}

//触发action的函数:每次触发一个action,currentListeners中的所有函数都要执行一遍

function dispatch(action) {

//如果action不是普通的对象,直接报错

if (!isPlainObject(action)) {

throw new Error(

'Actions must be plain objects. ' +

'Use custom middleware for async actions.'

)

}

//如果action没有type属性,直接报错:说明action对象必须要包含type字段

if (typeof action.type === 'undefined') {

throw new Error(

'Actions may not have an undefined "type" property. ' +

'Have you misspelled a constant?'

)

}

//如果当前正在触发另外一个action,直接报错

if (isDispatching) {

throw new Error('Reducers may not dispatch actions.')

}

try {

//先将标志位置为true

isDispatching = true

//执行传入的reducer函数,该函数返回一个新的state对象,并赋值给currentState变量

currentState = currentReducer(currentState, action)

} finally {

//reducer函数执行完成后,将isDispatching恢复成false,方便下次action的触发

isDispatching = false

}

//每一次触发一个action,所有的监听函数都要全部重新执行一遍,

//并且把上次得到的新的监听函数列表赋值成为当前的监听函数列表。这是一个懒操作,并不是在subscribe的时候就操作了,而是在dispatch的时候才操作

const listeners = currentListeners = nextListeners

for (let i = 0; i < listeners.length; i++) {

const listener = listeners[i]

listener()

}

//该dispatch函数的返回值是原来的action

return action

}

//替换reducer函数:这个函数允许运行时动态替换最开始调用createStore函数时传入的reducer,并且替换掉reducer之后,重新dispatch一个action,得到全新的currentState对象

function replaceReducer(nextReducer) {

//如果nextReducer不是函数,直接报错

if (typeof nextReducer !== 'function') {

throw new Error('Expected the nextReducer to be a function.')

}

//把新的reducer赋值给当前的currentReducer变量,得到一个全新的currentReducer

currentReducer = nextReducer

// 触发一个初始action:

// 1.这样就可以完成一次监听函数列表的全部调用

// 2.可以得到一个全新的currentState;

dispatch({type: ActionTypes.INIT})

}

function observable() {

const outerSubscribe = subscribe

return {

/**

* The minimal observable subscription method.

* @param {Object} observer Any object that can be used as an observer.

* The observer object should have a `next` method.

* @returns {subscription} An object with an `unsubscribe` method that can

* be used to unsubscribe the observable from the store, and prevent further

* emission of values from the observable.

*/

subscribe(observer) {

if (typeof observer !== 'object') {

throw new TypeError('Expected the observer to be an object.')

}

function observeState() {

if (observer.next) {

observer.next(getState())

}

}

observeState()

const unsubscribe = outerSubscribe(observeState)

return {unsubscribe}

},

[$$observable]() {

return this

}

}

}

五、初始化:

初始化很简单,一句代码,直接调用一次dispatch,就会执行所有的注册函数,并且执行reducer函数,生成初始化的state

//马上内部调用一次初始化的操作,根据传入的reducer函数,preloadedState生成一个全新的currentState和全新的reducer

dispatch({type: ActionTypes.INIT})

总结一下就是:

createStore函数定义了几个局部变量用于记录状态,主要包括currentState记录数据状态,currentListeners记录注册函数列表,currentReducer记录当前的reducer函数。

定义了几个函数用于修改上面的几个局部变量:主要包括getState函数用于获取currentState;replaceReducer用于替换currentReducer;subscribe用于修改currentListeners列表;dispatch用于触发currentReducer执行,生成新的currentState,并且,执行currentListeners列表中的每一个函数;

完整解析请参考我的github:https://github.com/abczhijia/...,如果对您有帮助,欢迎star,有任何问题也请指正。

(完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值