Redux
阅读 redux 源码
randomString 生成一个随机字符串
var randomString = function randomString() {
return Math.random().toString(36).substring(7).split('').join('.');
};
Number.prototype.toString(): toString() 方法返回指定 Number 对象的字符串表示形式。
numObj.toString([radix])
- 如果未指定radix参数,则默认值是10;
- 如果radix参数不在2-36之间,将会抛出一个RangeError
- 如果转换的基数大于10,则会使用字母来表示大于9的数字,比如基数为16的情况,则使用a到f的字母来表示10到15。
最近联想到的一个问题
[1, 2, 3, 2].map(parseInt) // [1, NaN, NaN, 2]
isPlainObject 判断是否是存粹的函数
function isPlainObject(obj) {
if (typeof obj !== 'object' || obj === null) return false;
var proto = obj;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(obj) === proto;
}
- obj 可能是从别的运行环境(比如浏览器中的同域iframe, nodejs中的vm)
- 当然也有可能使这段代码表现出不同的结果
let obj = Object.create(Object.create(null));
// 写成字面量的话是这样的:
let obj = {
__proto__: {
__proto__: null
}
};
isPlainObject(obj) // true
isPlainObject(null) // false
createStore 创建一颗Redux状态树 返回值是一个Store
- reducer 是一个函数,接受当前state和要处理的action,返回一个新的state
- preloadedState 初始化的state
- enhancer Store增强器
function createStore(reducer, preloadedState, enhancer) {
var _ref2;
// 判断如果 preloadedState 是函数 并且 enhancer 是函数 或者 enhancer 和 第四个参数是函数的话 就抛出错误 只允许一个增强器 需要将增强器合并
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
throw new Error('It looks like you are passing several store enhancers to ' + 'createStore(). This is not supported. Instead, compose them ' + 'together to a single function.');
}
// 如果preloadedState 是函数 并且 enhancer 未传 则把函数当作增强器赋值给 enhancer 初始化状态赋值为 undefined
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState;
preloadedState = undefined;
}
// 经历过上面的操作 如果这时候增强器不为空 但是 不是函数 则抛出错误
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.');
}
// enhancer 不为空的时候 就开始增强store 增强器函数接受到的是 createStore 这个函数 返回值是一个函数 接受两个参数 reducer, preloadedState
return enhancer(createStore)(reducer, preloadedState);
}
// 如果reducer 不是函数 能抛出错误 这里必须是个函数
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.');
}
// 当前reducer
var currentReducer = reducer;
// 当前state
var currentState = preloadedState;
// 当前监听器
var currentListeners = [];
var nextListeners = currentListeners;
var isDispatching = false;
// 实现一个currentListeners的浅复制
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice();
}
}
// 获取当前应用的 state ,不能在 dispatch 的时候获取, 否则会报错
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;
}
// 增加一个 listener, 每次 dispatch 的时候都会被调用, 返回值是可以去关闭订阅的函数,直接调用即可 remove
function subscribe(listener) {
// 订阅函数必须是一个可以被调用的 函数
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.');
}
// 如果还是在 dispatch 中调用会抛出错误
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#subscribelistener for more details.');
}
var isSubscribed = true;
// 浅复制一下 currentListener 至 nextListeners
ensureCanMutateNextListeners();
// 然后把 新增的这个listener 加在刚刚浅复制出来的末尾
nextListeners.push(listener);
// 这个就是返回值 取消订阅
return function unsubscribe() {
// 如果已经被取消订阅 则直接 return
if (!isSubscribed) {
return;
}
// 如上一样 千万不要在 dispatch 的时候做任何操作
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#subscribelistener for more details.');
}
// 标记已经被取消订阅 这是一个闭包函数 可以获取到每次调用各自的可以访问的参数 因此会有上面的 !isSubscribed 的判断
isSubscribed = false;
// dispatch 的时候 会生成一个当前的快照
ensureCanMutateNextListeners();
var index = nextListeners.indexOf(listener);
// 找出 然后删除
nextListeners.splice(index, 1);
// TODO: 然后把当前 currentListeners 清空
currentListeners = null;
};
}
// 更改 state 的唯一方式 action是没有副作用的对象(存粹) 返回传入的 action
function dispatch(action) {
// 判断 action 是否是存粹的 否则报错 需要用中间件处理
if (!isPlainObject(action)) {
throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
}
// 规定 action 必须要有 type 属性 而且不能是 undefined
if (typeof action.type === 'undefined') {
throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
}
// reducer 中 不能dispatch 原因往后看
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
try {
isDispatching = true;
// currentReducer 也就是参数的reducer 接受两个参数 当前state currentState 也可能是 undefined
currentState = currentReducer(currentState, action);
} finally {
// 当 reducer 执行完成 isDispatching 变成 false
isDispatching = false;
}
// 这里会跟上面联动 就是 unsubscribe 的时候要再次浅拷贝一下 每一次执行完之后 都会又一个最新的 listener 的快照
var listeners = currentListeners = nextListeners;
for (var i = 0; i < listeners.length; i++) {
var listener = listeners[i];
listener();
}
return action;
}
// 更换 reducer 并且改变 state 返回 空
function replaceReducer(nextReducer) {
// 还是一样 如果 reducer 不是函数就报错
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.');
}
currentReducer = nextReducer;
// 发起一个 replace 的 action
dispatch({
type: ActionTypes.REPLACE
});
}
function observable() {
var _ref;
// 上面定义的 subscribe 函数 接收一个 listener 作为参数 返回一个去掉当前 listener 的函数
var outerSubscribe = subscribe;
return _ref = {
// 一个 subscribe 函数 接收的参数是 一个 具有 next 属性的对象 返回的是一个具有 unsubscribede 的对象
subscribe: function subscribe(observer) {
// 如果 observer 不是对象报错
if (typeof observer !== 'object' || observer === null) {
throw new TypeError('Expected the observer to be an object.');
}
// https://github.com/tc39/proposal-observable
function observeState() {
if (observer.next) {
// 会传入当前的 state
observer.next(getState());
}
}
// 初始化一次
observeState();
// 注册 observeState listener
var unsubscribe = outerSubscribe(observeState);
return {
unsubscribe: unsubscribe
};
}
}, _ref[$$observable] = function () {
// TODO
return this;
}, _ref; // 这里是一个 逗号 表达式 最终返回的是 _ref
}
// 当创建一个 store 的时候 通过reducer创建初始化state
dispatch({
type: ActionTypes.INIT
});
// 同上 返回的是 _ref2 store 对象 包括一个dispatch / subscribe / getState / replaceReducer 还有个 observable 的属性
return _ref2 = {
dispatch: dispatch,
subscribe: subscribe,
getState: getState,
replaceReducer: replaceReducer
}, _ref2[$$observable] = observable, _ref2;
}
warning 在 console 中打印出警告的信息
function warning(message) {
// 一个好的习惯 在调用之前判断 console 是否存在 适用于不同的上下文
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(message);
}
try {
throw new Error(message);
} catch (e) {}
}
getUndefinedStateErrorMessage 当 reducer 通过 action 返回undefined 的时候的错误提示信息
function getUndefinedStateErrorMessage(key, action) {
var actionType = action && action.type;
var actionDescription = actionType && "action \"" + String(actionType) + "\"" || 'an action';
return "Given " + actionDescription + ", reducer \"" + key + "\" returned undefined. " + "To ignore an action, you must explicitly return the previous state. " + "If you want this reducer to hold no value, you can return null instead of undefined.";
}
getUnexpectedStateShapeWarningMessage 通过对比 state 和 reducer 的属性 发出警告
function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {
var reducerKeys = Object.keys(reducers);
var argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';
// 不能没有 reducer,否则报错
if (reducerKeys.length === 0) {
return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
}
// 如果不是存粹的 state 也是要报错
if (!isPlainObject(inputState)) {
return "The " + argumentName + " has unexpected type of \"" + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + "\". Expected argument to be an object with the following " + ("keys: \"" + reducerKeys.join('", "') + "\"");
}
var unexpectedKeys = Object.keys(inputState).filter(function (key) {
return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key];
});
unexpectedKeys.forEach(function (key) {
unexpectedKeyCache[key] = true;
});
// REPLACE 除外
if (action && action.type === ActionTypes.REPLACE) return;
// 不然必须要 每个 state 的属性 存在对应的 reducer
if (unexpectedKeys.length > 0) {
return "Unexpected " + (unexpectedKeys.length > 1 ? 'keys' : 'key') + " " + ("\"" + unexpectedKeys.join('", "') + "\" found in " + argumentName + ". ") + "Expected to find one of the known reducer keys instead: " + ("\"" + reducerKeys.join('", "') + "\". Unexpected keys will be ignored.");
}
}
assertReducerShape 判断 reducers 是否都是合法的
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(function (key) {
var reducer = reducers[key];
var initialState = reducer(undefined, {
type: ActionTypes.INIT
});
// 如果初始化时候 或者 state 给 undefined 的时候 要返回初始化的 state 否则报错
if (typeof initialState === 'undefined') {
throw new Error("Reducer \"" + key + "\" returned undefined during initialization. " + "If the state passed to the reducer is undefined, you must " + "explicitly return the initial state. The initial state may " + "not be undefined. If you don't want to set a value for this reducer, " + "you can use null instead of undefined.");
}
// 要能接的住一个 未知的 action 有个 default 返回当前的state 否则会报错
if (typeof reducer(undefined, {
type: ActionTypes.PROBE_UNKNOWN_ACTION()
}) === 'undefined') {
throw new Error("Reducer \"" + key + "\" returned undefined when probed with a random type. " + ("Don't try to handle " + ActionTypes.INIT + " or other actions in \"redux/*\" ") + "namespace. They are considered private. Instead, you must return the " + "current state for any unknown actions, unless it is undefined, " + "in which case you must return the initial state, regardless of the " + "action type. The initial state may not be undefined, but can be null.");
}
});
}
combineReducers 整合 reducers 变成一个单一的reducer / 返回值是一个函数 接收初始化 state,接收一个 action 返回更改过后的 state
function combineReducers(reducers) {
var reducerKeys = Object.keys(reducers);
var finalReducers = {};
// 遍历整个 reducer
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
if (process.env.NODE_ENV !== 'production') {
// 如果不是生产环境 就会在控制台 打印警告信息
if (typeof reducers[key] === 'undefined') {
warning("No reducer provided for key \"" + key + "\"");
}
}
// 通过判断是否是函数 最终的 reducers 形成 也可以去重 防止传入的 reducers 是有重复 key
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key];
}
}
var finalReducerKeys = Object.keys(finalReducers);
var unexpectedKeyCache;
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {};
}
var shapeAssertionError;
try {
// 判断 reducers 是否合法
assertReducerShape(finalReducers);
} catch (e) {
shapeAssertionError = e;
}
// 返回值是一个函数 接收一个state 以及 action
return function combination(state, action) {
// 如果 state 未传 则给一个空对象
if (state === void 0) {
state = {};
}
// 上面的错误 如果发现有 reducer 不符合规范 就抛出错误
if (shapeAssertionError) {
throw shapeAssertionError;
}
if (process.env.NODE_ENV !== 'production') {
// 如果不是生产环境 检查传入的 state 是否有key 没有对应的 reducer
var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
if (warningMessage) {
warning(warningMessage);
}
}
var hasChanged = false;
var nextState = {};
// 遍历最终的 reducers
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key];
// previousStateForKey 可能是 undefined 所以 reducer 必须要有一个默认 state
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
// 如果没有给默认的state 就报错
var errorMessage = getUndefinedStateErrorMessage(_key, action);
throw new Error(errorMessage);
}
nextState[_key] = nextStateForKey;
// 通过对比 state 有没有变化
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
// 如果 reducer 改变了 state 里面的值 或者 reducer 和 state 值对不上 则返回最新的 state => nextState
return hasChanged ? nextState : state;
};
}
bindActionCreator 接收一个 actionCreator 函数 第二个参数是 dispatch
function bindActionCreator(actionCreator, dispatch) {
// 返回一个函数 dispatch 一个 action
return function () {
return dispatch(actionCreator.apply(this, arguments));
};
}
bindActionCreators 第一个参数 可以是function 或者是 值是 actionCreator 的对象 第二个参数是 dispatch 返回值是用dispatch的函数 或者 以其为值的 对象
function bindActionCreators(actionCreators, dispatch) {
// 如果 第一个参数 是函数 则直接返回被 dispatch 包裹的函数
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch);
}
// 如果不是对象 排除到 null 的情况 则抛出错误
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 \"import * as ActionCreators from\"?");
}
var boundActionCreators = {};
for (var key in actionCreators) {
// hasOwnProperty
var actionCreator = actionCreators[key];
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
}
}
// 返回值 就是每个都用 dispatch 包裹的 函数 看上一个函数
return boundActionCreators;
}
_defineProperty Object.defineProperty 的函数
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
ownKeys 接收一个参数 和 一个是否可以枚举的参数 返回所有的 key
function ownKeys(object, enumerableOnly) {
// 对象上所有的 key 但是不包括 symbol 的 key
var keys = Object.keys(object);
// 加上 Symbol 的 key
if (Object.getOwnPropertySymbols) {
keys.push.apply(keys, Object.getOwnPropertySymbols(object));
}
if (enumerableOnly) keys = keys.filter(function (sym) {
// 访问器属性
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
return keys;
}
_objectSpread2
function _objectSpread2(target) {
// 遍历参数 如果都没有 直接返回
for (var i = 1; i < arguments.length; i++) {
// 不能是 null 因为不能对 null 或者 undefined 使用 Object.getOwnPropertyDescriptors
var source = arguments[i] != null ? arguments[i] : {};
// 遍历所有参数 整合成一个 Object
if (i % 2) {
ownKeys(source, true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(source).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
compose 柯里化 (...args) => f(g(h(...args))) 从右向左依次执行
function compose() {
// 遍历参数 生成一个所有参数的数组 转换类数组类型 成 数组
for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) {
funcs[_key] = arguments[_key];
}
// 如果没有参数 则生成一个 函数 输入什么 直接返回 什么
if (funcs.length === 0) {
return function (arg) {
return arg;
};
}
// 如果函数只有一个 也是直接返回当前函数
if (funcs.length === 1) {
return funcs[0];
}
// 一个 reduce 函数 从左到右 依次包裹 最后面的 在最里面
return funcs.reduce(function (a, b) {
return function () {
return a(b.apply(void 0, arguments));
};
});
}
applyMiddleware 接收一些中间件 生成一个完整的增强器
function applyMiddleware() {
// 同上 转成中间件的数组
for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) {
middlewares[_key] = arguments[_key];
}
// 返回一个函数 接收的参数 是 createStore
return function (createStore) {
return function () {
// 生成一个 store
var store = createStore.apply(void 0, arguments);
// 不能在构建 middleware 的时候 dispatch 因为如果调用的话 其余中间件 也不会收到这个dispatch
var _dispatch = function dispatch() {
throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.');
};
// 先传入一个能够报错的 dispatch 防止在构建 middleware 过程中 调用 dispatch
var middlewareAPI = {
getState: store.getState,
dispatch: function dispatch() {
return _dispatch.apply(void 0, arguments);
}
};
// 生成一个 middleware 的 数组
var chain = middlewares.map(function (middleware) {
return middleware(middlewareAPI);
});
// 生成一个增强的 dispatch chain中 中间件 接收一个 {getState, dispatch} 返回一个函数接收一个dispatch 的函数
= compose.apply(void 0, chain)(store.dispatch);
// 生成一个增强过的 store 对象
return _objectSpread2({}, store, {
dispatch: _dispatch
});
};
};
}
isCrushed 假函数
function isCrushed() {}
// 如果不是生产环境 但是函数名字被压缩过了 就告警
if (process.env.NODE_ENV !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed') {
warning('You are currently using minified code outside of NODE_ENV === "production". ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' + 'to ensure you have the correct code for your production build.');
}
以上就是全部 redux 代码
下面结合例子再次巩固
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import reducers from './reducers';
// 假定有两个中间件
import thunk from 'redux-thunk';
// https://github.com/fcomb/redux-logger.git
const logMiddleware = ({ getState }) => dispatch => {
return action => {
const current prevState = getState()
const returnValue = dispatch(action)
const nextValue = getState()
if (typeof console !== 'undefined') {
const message = `action ${action.type} @ ${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}`;
try {
console.group(message);
} catch(e) {
console.log('NOT GROUP');
}
console.log(`%c prev state`, `color: #9E9E9E; font-weight: bold`, prevState);
console.log(`%c action`, `color: #03A9F4; font-weight: bold`, action);
console.log(`%c next state`, `color: #4CAF50; font-weight: bold`, nextState);
try {
console.groupEnd('—— log end ——');
} catch(e) {
console.log('—— log end ——');
}
}
// 返回值若不变 能就是 action
return returnValue;
}
}
// 生成中间件集合
const createStoreWithMiddleware = applyMiddleware(logger, thunk)(createStore);
// 生成 reducer
const reducer = combineReducers(reducers);
// 然后生成的全局 store
const store = createStoreWithMiddleware(reducer);