20180914 redux - createStore源碼學(xué)習(xí)和測(cè)試
標(biāo)簽:
JavaScript
坐在那里看源码很费劲,还是跟着手敲了一遍,把一些例子贴出来,能解有缘人的一丝疑惑也算是功德圆满。水平有限,但是挡不住我们进步的脚步 (∇*)
看了一点createStore的源码
1. 调用dispatch的时候,会统一调用一遍subscribe中的listener; 也就是说,应该在dispatch之前就要生成相应的listener
测试图片.png
父组件
constructor() { super(); console.log(''); console.log('--- parent constructor == start ----'); store.subscribe(() => { console.log('--- parent constructor == subscribe---', store.getState()) }); console.log('--- parent constructor == end----'); console.log(''); } componentDidMount() { console.log(''); console.log('--- parent didMount == start ----'); store.subscribe(() => { console.log('--- parent didMount == subscribe---', store.getState()) }); console.log('--- parent didMount == end ----'); console.log(''); }
子组件
constructor(){ super(); console.log('==== child - dispatch === start --'); store.dispatch({ type: 'TO_PARENT' }); console.log('==== child - dispatch === end =='); }
2. 解决上面问题的方法
import $$observable from 'symbol-observable' store[$$observable]().subscribe({ next: (state) => { console.log('---$$observable--', state); } }); // 牛逼不,惊喜不??? 终究还是这些牛逼的人已经想到解决办法了,(^∇^*)
3. 下面是源码的注释
import $$observable from 'symbol-observable'// actionconst randomString = () => Math.random() .toString(36) .substring(7) .split('') .join('.')const ActionTypes = { INIT: `@@redux/INIT${randomString()}`, REPLACE: `@@redux/REPLACE${randomString()}`, PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`};// 判断一个obj是不是纯对象// 如果是纯对象,最底层的原型prototype都应该是继承自Objectfunction isPlainObject(obj) { if (typeof obj !== 'object' || obj === null) return false; let proto = obj; while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto); } return Object.getPrototypeOf(obj) === proto; }/** * 读不懂,只能写着看看,o(╥﹏╥)o * @param reducer * @param preloadedState * @param enhancer */export default function createStore(reducer, preloadedState, enhancer) { // preloadedState 是函数且 enhancer未定义 // enhancer 和 preloadedState 互换 if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState; preloadedState = undefined; console.log('===test==1=') } // enhancer 是函数的时候使用如下方法 if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } // 用enhancer包装一次,调用createStore,没有enhancer的方法 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) { console.log('====arr-listener.slice===='); nextListeners = currentListeners.slice(); } } // 获取当前的state 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; } /** * 订阅的方法 * 1. 把当前的传入的listener放入队列 * 2. 在放入之前,更新队列应该确定是不是要复制一次初始的队列 * @param listener * @returns {unsubscribe} 返回一个解除订阅的方法 */ function subscribe(listener) { console.log('==== subscribe = inner ==='); 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; 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); } } /** * 事件派发 * 时间派发的时候做了两件事: * 1. 用当前的reducer去修改state * 2. 把订阅subscribe中的listener全部调用一遍 * @param action * @returns {*} */ 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; currentState = currentReducer(currentState, action); } finally { isDispatching = false; } // 这里是执行的是subscribe中的回调函数 // ====> 注意这里是dispatch;却在调用subscribe的方法,注意 const listeners = (currentListeners = nextListeners); for (let i = 0; i < listeners.length; i++) { const listener = listeners[i]; listener(); } return action; } /*------------ 下面这两个方法不知道是什么用意 ---------------*/ function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer; dispatch({type: ActionTypes.REPLACE}); } /** * 利用 $$observable 创建了一个能够被观测的对象, * 当对象状态发生变化的时候,能被观察到 * For more information, see the observable proposal: * https://github.com/tc39/proposal-observable * https://github.com/benlesh/symbol-observable * @returns {*} */ function observable() { const outerSubscribe = subscribe; return { subscribe(observer) { if (typeof observer !== 'object' || observer === null) { throw new TypeError('Expected the observer to be an object.') } console.log('~~~~ subscribe ~~~~~~'); function observeState() { if (observer.next) { observer.next(getState()); } } observeState(); const unsubscribe = outerSubscribe(observeState); return {unsubscribe}; }, [$$observable]() { return this } } } dispatch({type: ActionTypes.INIT}); return { getState, subscribe, dispatch, [$$observable]: observable }; }
作者:Aaron_Alphabet
链接:https://www.jianshu.com/p/5da4338e6008
點(diǎn)擊查看更多內(nèi)容
為 TA 點(diǎn)贊
評(píng)論
評(píng)論
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章
正在加載中
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦