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(".");
}
以上。