Redux 的几个核心函数源码
根据订阅发布设计模式看了要模仿的一个功能,看着看着坑越挖越多,涉及到了redux 。顺便尝试吃了一下 redux 的几个核心函数的源码,初生涩隐有启发并作记录。
Redux 的几个核心函数源码
combineReducers
function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers);
const finalReducers = {};
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i];
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning('No reducer provided for key'
$ {
key
});
}
}
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers);
let unexpectedKeyCache;
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {};
}
let shapeAssertionError;
try {
// 判断传入的 reducer 格式是否正确,函数作用为传入的 type 不存在时,是否会返回默认值
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e;
}
return function combination(state = {}, action) {
// 如果存在不返回默认值的 reducer,抛出异常
if (shapeAssertionError) {
throw shapeAssertionError
}
// 发出警告 不影响程序执行
if (process.env.NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
if (warningMessage) {
warning(warningMessage)
}
}
// 记录是否发生了变化,重点
let hasChanged = false;
// 要返回的下一个状态
const nextState = {};
for (let i = 0; i < finalReducers.length; i++) {
const key = finalReducerKeys[i];
const reducer = finalReducers[key];
// 使用该函数的要求,每个 reducer 的 key 值要和当前操作的 state 的参数同名,比如传入的 card:cardReducer,那么 state 操作的参数就必须是 state.card
const previousStateForKey = state[key];
const nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action);
throw new Error(errorMessage);
}
// 执行了 reducer 之后的结果
nextState[key] = nextStateForKey;
// 每次执行之后的结果,再综合上一次得到的 hasChanged,得到最终的 state 是否发生了变化
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
// 如果发生了变化,就要返回新的 state -> nextState
return hasChanged ? nextState : state;
}
}
bindActionCreators
function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(..args));
}
function bindActionCreators(actionCreators, dispatch) {
// 可以只传入一个函数作为参数,它会给这个函数的返回结果添加 dispatch 处理
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch);
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function,instead received ${actionCreators === null ? 'null' : typeof actionCreators}` +
`Did you write 'import ActionCreators from' instead of 'immport * as ActionCreators from'?`);
}
const keys = Object.keys(actionCreators);
const boundActionCreators = {};
for (let i = 0; i < keys.length++; i++) {
const key = keys[i];
const actionCreator = actionCreator[key];
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
}
}
// 为其添加 dispatch 并返回
return boundActionCreators;
}
compose
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce(
(a, b) =>
(...args) =>
a(b(...args))
);
}
applyMiddleware
function applyMiddleware(...middlewares) {
return createStore => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer);
let dispatch = store.dispatch;
// 定义一个存储中间件函数的列表
let chain = [];
const middlewareAPI = {
getState: store.getState,
dispatch: action => dispatch(action)
};
// 这里看出 middleware 需要符合一个规则,接受 getState() 和 dispatch 作为参数
chain = middlewares.map(middleware => middleware(middlewareAPI));
dispatch = compose(...chain)(store.dispatch);
return {
...store, // 原来的 store 结构
dispatch // 增强过的
};
};
}
createStore(重点)
function createStore(reducer, preloadedState, enhancer) {
// 这里操作表明,可以不传第二个参数,不传默认为 undefined
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState;
preloadedState = undefined;
}
if (typeof enhancer !== 'undefined') {
// enhancer 必须是一个函数
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function');
}
// 如果传递 enhancer,则把 createStore 作为参数传递进去,第三个参数不穿也可以,applymiddleware 中会将 createStore 执行并返回
return enhancer(createStore)(reducer, preloadedState);
}
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function');
}
let currentReducer = reducer;
// 当前的state
let currentState = preloadedState;
// 当前的listeners
let currentListeners = [];
let nextListeners = currentListeners;
// 是否在分发
let isDispatching = false;
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice(); // 浅拷贝
}
}
function getState() {
return currentState;
}
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function');
}
let isSubscribed = true;
ensureCanMutateNextListeners();
nextListeners.push(listener);
return function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextListeners();
const index = nextListeners.indexOf(listener);
nextListeners.splice(index, 1);
};
}
function dispatch(action) {
// action 必须是一个对象{type:'xxx'}
if (!isPlainObject(action)) {
throw new Error('Actions must be plain object,Use custom middleware for async actions');
}
// 对象必须有 type 属性(唯一确定一个 action,不能重复)
if (typeof action.type === 'undefined') {
throw new Error('Actions may not have an undefined "type" property.Have you misspelled a constant');
}
// 不能同时执行两个 dispatch
if (isDispatching) {
throw new Error('Reducers may not dispatch actions');
}
try {
isDispatching = true;
//不论第一次传入currentState是否有值,都会根据第一次的reducer返回默认值
//比如首次执行createStore就会传入一个几乎不会存在于reducer的case中的类型,这样就可以返回第一次传入reducer的默认值了。
currentState = currentReducer(currentState, action);
} finally {
//放开dispatch入口
isDispatching = false;
}
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.INIT
});
}
// 一个正规的 reducer 都会返回一个默认值,执行这一步 是为了返回 reducer 的默认值
dispatch({
type: ActionTypes.INIT
});
return {
dispatch,
subscribe,
getState,
replaceReducer
};
}