目錄
- 1,分析
- 2,實現
- 2.1,基礎實現
- 2.2,優化
- 2.2.1,隨機字符串
- 2.2.2,action 的判斷
- 2.2.2,監聽器的優化
- 2.3,最終形態
1,分析
createStore()
,參數1為 reducer
,參數2為初始化的 state
(中間件參數,之后的文章會介紹)。返回的 store
對象有以下屬性:
dispatch
方法,用于分發action
。getState
方法,用于得到最新的state
。subscribe
方法,用于在state
發生變化時執行。
2,實現
2.1,基礎實現
export const createStore = (reducer, defaultState) => {let currentReducer = reducer;let currentState = defaultState;let listeners = [];const dispatch = (action) => {currentState = currentReducer(currentState, action);// 每次更新時,遍歷監聽器。for (const listener of listeners) {listener();}};const getState = () => {return currentState;};const subscribe = (listener) => {listeners.push(listener);// 取消監聽return () => {listeners = listeners.filter((f) => f !== listener);};};// createStore 創建時會調用一次。dispatch({type: "@@redux/INITg.p.0.c.e.f",});return {dispatch,getState,subscribe,};
};
2.2,優化
2.2.1,隨機字符串
createStore
創建時調用 dispatch()
傳入的 type
是隨機 36位 字符串。可以這樣生成:
Math.random().toString(36) // '0.ge0p9nwtid7'
Math.random().toString(36).substring(2, 8) // 'ge0p9n'
Math.random().toString(36).substring(2, 8).split('').join('.') // 'g.e.0.p.9.n'
export const createStore = (reducer, defaultState) => {// ...dispatch({type: `@@redux/INIT${getRandomString()}`,});// ...
};function getRandomString() {return Math.random().toString(36).substring(2, 8).split('').join('.')
}
2.2.2,action 的判斷
action
有一些限制:
- 必須是一個平面對象。
- 必須有
type
屬性。
const dispatch = (action) => {if (typeof action !== "object" || Object.getPrototypeOf(action) !== Object.prototype) {throw new Error("action 必須是一個 plain Object");}if (action.type === undefined) {throw new Error("action 必須有 type 屬性");}// ...
};
2.2.2,監聽器的優化
監聽器返回的函數執行一次之后,再次執行時應該立即返回且什么都不做。因為對應的監聽器已經卸載了。
const subscribe = (listener) => {listeners.push(listener);let isRemove = false;return () => {if (isRemove) {return;} else {isRemove = true;listeners = listeners.filter((f) => f !== listener);}};
};
2.3,最終形態
export const createStore = (reducer, defaultState) => {let currentReducer = reducer;let currentState = defaultState;let listeners = [];const dispatch = (action) => {if (typeof action !== "object" || Object.getPrototypeOf(action) !== Object.prototype) {throw new Error("action 必須是一個 plain Object");}if (action.type === undefined) {throw new Error("action 必須有 type 屬性");}currentState = currentReducer(currentState, action);// 每次更新時,遍歷監聽器。for (const listener of listeners) {listener();}};const getState = () => {return currentState;};const subscribe = (listener) => {listeners.push(listener);let isRemove = false;// 取消監聽return () => {if (isRemove) {return;} else {isRemove = true;listeners = listeners.filter((f) => f !== listener);}};};// createStore 創建時會調用一次。dispatch({type: `@@redux/INIT${getRandomString}`,});return {dispatch,getState,subscribe,};
};function getRandomString() {return Math.random().toString(36).substring(2, 8).split("").join(".");
}
以上。