redux 源码浅析 (2)

还有一个额外的 observable 对象:

// 一个 Symbol.observable 的 polyfill import $$observable from 'symbol-observable' function observable() { // subscribe 就是 store.subscribe const outerSubscribe = subscribe return { subscribe(observer) { // 如果 observer 不是对象或者为 null 则抛出错误 function observeState() { if (observer.next) { // next 的入参为 当然 reducer 的值 observer.next(getState()) } } observeState() // 添加了监听 const unsubscribe = outerSubscribe(observeState) return {unsubscribe} }, // 获取到当前 对象, $$observable 值是一个 symbol [$$observable]() { return this } } }

这里使用了 tc39 里未上线的标准代码 Symbol.observable, 如果你使用或者了解过 rxjs, 那么这个对于你来说就是很简单的, 如果不熟悉,
可以看看这篇文章: https://juejin.cn/post/6844903714998730766

剩余代码 function createStore() { // 省略 // 初始化了下值 dispatch({type: ActionTypes.INIT}) // 返回 return { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } } combineReducers 使用 // 可以接受多个 reducer, 实现一种 module 的功能 rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer}) // 返回值 { potato: { // 某些属性 } , tomato: { // 某些属性 } } const store = createStore(rootReducer, { potato: { // 初始值 } })

有一点需要注意的是, reducer 都是需要默认值的,如:

function counterReducer(state = {value: 0}, action) { //... } 源码解析 combineReducers

先看 combineReducers 执行之后产生了什么

function combineReducers(reducers) { // 第一步是获取 key, 他是一个数组 const reducerKeys = Object.keys(reducers) const finalReducers = {} // 遍历 reducers, 赋值到 finalReducers 中, 确保 reducer 是一个函数, 不是函数则过滤 for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] // 省略 reducers[key] 如果是 undefined 抛出错误 if (typeof reducers[key] === 'function') { finalReducers[key] = reducers[key] } } // finalReducerKeys 一般来说是和 reducerKeys 相同的 const finalReducerKeys = Object.keys(finalReducers) //定义了两个遍历 let unexpectedKeyCache let shapeAssertionError try { // 此函数后面会详细讲述 // 答题作用就是确认 finalReducers 中都是有初始值的 assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e } //... }

再看他又返回了什么(记住结果必然也是一个 reducer)

function combineReducers(reducers) { //... return function combination(state = {}, action) { // 如果 assertReducerShape 出错则抛出错误 if (shapeAssertionError) { throw shapeAssertionError } // 忽略非 production 代码 // 预先定义一些变量 let hasChanged = false const nextState = {} // 循环 finalReducerKeys for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key] // 这是一开始的值 const nextStateForKey = reducer(previousStateForKey, action) // 通过 reducer 再次生成值 // 如果 nextStateForKey === undefined 则再次抛出异常 // 给 nextState 赋值 nextState[key] = nextStateForKey // 判断是否改变 (初始值是 false) 判断简单的使用 !== 来比较 // 如果已经为 true 就一直为 true 了 hasChanged = hasChanged || nextStateForKey !== previousStateForKey } // 循环后再次对 true 做出判断 // 是否少了 reducer 而造成误判 hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length // 如果改变了 返回新值, 否则返回旧值 return hasChanged ? nextState : state } }

combineReducers 基本就是上述两个函数的结合, 通过循环遍历所有的 reducer 计算出值

assertReducerShape function assertReducerShape(reducers) { Object.keys(reducers).forEach(key => { // 遍历参数里的 reducer const reducer = reducers[key] //执行初始操作 产生初始值都有初始值 const initialState = reducer(undefined, {type: ActionTypes.INIT}) //... 如果 initialState 是 undefined 则抛出错误 // 如果 reducer 执行未知操作 返回的是 undefined 则抛出错误 // 情景: 当前 reducer 使用了 ActionTypes.INIT 来产生值, 这能够通过上一步 // 但在这一步就会被检测出来 if ( typeof reducer(undefined, { type: ActionTypes.PROBE_UNKNOWN_ACTION() }) === 'undefined' ) { //... 抛出错误 } }) }

这里我们可以知道一点, 所有 reducer 我们都必须要有一个初始值, 而且他不能是 undefined, 可以是 null

compose

这里需要先讲 compose 的使用 才能顺带过渡到下面

使用

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfsgs.html