redux教程之源码解析createStore
redux源码
redux的源码很简单,分为以下几部分
- createStore
- combineReducers
- applyMiddleware
- compose
- bindActionCreators
createStore即入口函数生成store,将reducer和middleware关联起来
combineReducers即将分散的reducer最终合并成一个统一的reducer
applyMiddleware即将多个中间件一次合并到reducer中,生成一个最终的reducer
compose是一个函数,从右到左来组合多个函数。将中间件数组依次从后向前。将后一个中间件包裹在前一个中间件函数中。
//示例代码 import { createStore } from 'redux' function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return state.concat([action.text]) default: return state } } let store = createStore(todos, ['Use Redux']) store.dispatch({ type: 'ADD_TODO', text: 'Read the docs' }) console.log(store.getState()) // [ 'Use Redux', 'Read the docs' ]
createStore即入口函数: export default function createStore(reducer, preloadedState, enhancer) { /** 入口参数判断*/ if ( (typeof preloadedState === 'function' && typeof enhancer === 'function') || (typeof enhancer === 'function' && typeof arguments[3] === 'function') ) { /** enhancer即中间件,中间件需要合在一起传入createStore*/ throw new Error( 'It looks like you are passing several store enhancers to ' + 'createStore(). This is not supported. Instead, compose them ' + 'together to a single function' ) } /** preloadedState可以省略*/ if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } /**middleware需要为函数 */ 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 let currentState = preloadedState let currentListeners = [] let nextListeners = currentListeners let isDispatching = false /** 将新的监听函数和当前监听函数隔离开*/ function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } } /** * Reads the state tree managed by the store. * * @returns {any} The current state tree of your application. */ /**获取Store的currentState */ 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 } /**绑定监听函数,即reducer执行完后后执行这些函数 */ function subscribe(listener) { if (typeof listener !== 'function') { throw new Error('Expected the listener to be a function.') } if (isDispatching) { throw new Error( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.' ) } let isSubscribed = true /**新生成一个listener数组,以免push时影响 currentListener*/ 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 /**又出现了这个函数,确认是否可以变为下一个监听,z不知道这个函数有什么用 */ ensureCanMutateNextListeners() /**确定解除绑定函数的位置并删除它 */ const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } } function dispatch(action) { /**判断action是否为纯对象 */ if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } /**action必须有type */ if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } try { /**将isDispatching赋值为true,且开始执行reducer修改state */ isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } /**执行完后通知listeners */ const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } /**替换reducer,且初始化state */ function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer //初始化state dispatch({ type: ActionTypes.REPLACE }) } function observable() { const outerSubscribe = subscribe return { subscribe(observer) { if (typeof observer !== 'object' || observer === null) { 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 } } } // When a store is created, an "INIT" action is dispatched so that every // reducer returns their initial state. This effectively populates // the initial state tree. dispatch({ type: ActionTypes.INIT }) return { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } }
前端笔记0-0