坐在那里看源碼很費(fèi)勁,還是跟著手敲了一遍,把一些例子貼出來,能解有緣人的一絲疑惑也算是功德圓滿。水平有限,但是擋不住我們進(jìn)步的腳步 ?(?*)
看了一點(diǎn)createStore的源碼
1. 調(diào)用dispatch的時候,會統(tǒng)一調(diào)用一遍subscribe中的listener; 也就是說,應(yīng)該在dispatch之前就要生成相應(yīng)的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);
}
});
// 牛逼不,驚喜不??? 終究還是這些牛逼的人已經(jīng)想到解決辦法了,?(^?^*)
3. 下面是源碼的注釋
import $$observable from 'symbol-observable'
// action
const 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都應(yīng)該是繼承自O(shè)bject
function 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 是函數(shù)且 enhancer未定義
// enhancer 和 preloadedState 互換
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState;
preloadedState = undefined;
console.log('===test==1=')
}
// enhancer 是函數(shù)的時候使用如下方法
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 用enhancer包裝一次,調(diào)用createStore,沒有enhancer的方法
return enhancer(createStore)(reducer, preloadedState);
}
// reducer 不是函數(shù)的時候
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();
}
}
// 獲取當(dāng)前的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. 把當(dāng)前的傳入的listener放入隊(duì)列
* 2. 在放入之前,更新隊(duì)列應(yīng)該確定是不是要復(fù)制一次初始的隊(duì)列
* @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(); // 復(fù)制一次當(dāng)前的監(jiān)聽器隊(duì)列
nextListeners.push(listener); // 將當(dāng)前的監(jiān)聽器放入隊(duì)列
// 返回一個取消訂閱的方法
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);
}
}
/**
* 事件派發(fā)
* 時間派發(fā)的時候做了兩件事:
* 1. 用當(dāng)前的reducer去修改state
* 2. 把訂閱subscribe中的listener全部調(diào)用一遍
* @param action
* @returns {*}
*/
function dispatch(action) {
// action 應(yīng)該是一個純對象 { }
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
);
}
// 派發(fā)必須是通過action.type
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
// 判斷是否在派發(fā)狀態(tài)
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
// 這塊的作用感覺就是狀態(tài)的切換,但是為什么呢??
try {
isDispatching = true;
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
// 這里是執(zhí)行的是subscribe中的回調(diào)函數(shù)
// ====> 注意這里是dispatch;卻在調(diào)用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 創(chuàng)建了一個能夠被觀測的對象,
* 當(dāng)對象狀態(tài)發(fā)生變化的時候,能被觀察到
* 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
};
}
代碼終究是一種實(shí)踐藝術(shù),敲一敲吧。
士人有百折不回之真心,才有萬變不窮之妙用。立業(yè)建功,事事要從實(shí)地著腳,若少慕聲聞,便成偽果;講道修德,念念要從虛處立基,若稍計功效,便落塵情。 ---------------- 《菜根譚》