理解redux
redux为什么引入redux以 Flux与reduxFluxFlux是facebook提出的一种架构思想,与
reduxfacebook提供的 redux与Flux的区别
入口
export {
createStore,// 创建store
combineReducers,// 合并reducer
bindActionCreators,applyMiddleware,compose
}
其中还有一个 isCrushed.name !== 'isCrushed' // 压缩后函数名字会变短
下面来一个一个的看 compose
const x = 10,add = x => x + 10,sub = x => x - 20,sup = x => x * 10;
// 原生方式嵌套实现
add(
sup(
sub( add(x) ) ) );
// 利用compose改进
const fn = compose(add,sup,sub,add);
fn(x);
对比上面代码,利用 export default 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))
)
);
};
createStore什么是store
解析依赖函数该模块依赖了 function isPlainObject(val) {
// 非对象的情况直接返回false
if (!isObjectLike(value) || baseGetTag(value) != '[object Object]') {
return false
}
const proto = Object.getPrototypeOf(value)
// 针对Object.create(null)创建出来的对象
if (proto === null) {
return true
}
const Ctor = hasOwnProperty.call(proto,'constructor') && proto.constructor
// prototype.constructor === Object
return typeof Ctor == 'function' && Ctor instanceof Ctor &&
funcToString.call(Ctor) == objectCtorString
}
主体函数// 内部的action,用于reset
export const ActionTypes = {
INIT: '@@redux/INIT'
};
/* * 创建store * reducer reducer函数 * preloadedState 初始状态 * enhancer 增强函数,对createStoren能力进行增强,如devtools */
export default function createStore(reducer,preloadedState,enhancer) {
// 参数修正
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.');
}
// 返回已经增强后的store
return enhancer(createStore)(reducer,preloadedState);
}
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.');
}
// 记录当前值
let currentReducer = reducer;
let currentState = preloadedState;
// 监听store变化的监听器(一些回调函数)
let currentListeners = [];
let nextListeners = currentListeners;
// 是否处于dispatch的过程中
let isDispatching = false;
/**** 看下面文字解释 ****/
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice();
}
}
// 给store新增一个监听器
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.index(listener);
nextListeners.splice(index,1);
};
}
// 返回当前的状态
function getState() {
return currentState;
}
function dispatch(action) {
// 一些类型检测
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true;
// 根据recuder来更新当前状态
currentState = currentReducer(currentState,action);
} finally {
isDispatching = false;
}
const listeners = currentListeners = nextListeners;
// 发布事件
for (let i = 0; i < listeners.length; i++) {
const listener = listeners;
listener();
}
return action;
}
// 更新当前reducer,重置store
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.');
}
currentReducer = nextReducer;
dispatch({ type: ActionTypes.INIT });
}
// 初始化store
dispatch({ type: ActionTypes.INIT });
// 与Rxjs这种交互,根本看不懂--
function observable() { ... }
return {
getState,subscribe,dispatch,replaceReducer,[$$observable]: observable
};
};
需要注意的有以下几点:
applyMiddleware中间件, const calc = (obj) => obj.value + 20;
// 简单的模拟下stroe
const obj = { calc };
// 加强fn函数
function applyMiddleware(fn,middlewares) {
middlewares = middlewares.slice();
middlewares.reverse();
// 每次改变fn,一次扩展一个功能
let { calc } = obj;
middlewares.forEach(
middleware => calc = middleware(obj)(calc)
);
return calc;
}
// arrow function is cool!!!
const logger = obj => next => num => {
console.log(`num is ${num.value}`);
let result = next(num);
console.log(`finish calc,result is ${result}`);
return result;
};
const check = obj => next => num => {
console.log(`typeof num.value is ${typeof num.value}`);
let result = next(num);
return result;
};
const fn = applyMiddleware(obj,[check,logger]);
fn({ value: 50 });
在上面简单的例子中为 export default function applyMiddleware(...middlewares) {
// 利用闭包保存下来了middlewares
return (createStore) => (reducer,preloadadState,enhancer) => {
const store = createStore(reducer,enhancer);
let dispatch = store.dispatch;
let chain = [];
// middleware不会改变store,利用闭包保存
const middlewareAPI = {
getState: store.getState,dispatch: (action) => dispatch(action)
};
// chain中的元素仍未函数
// 接受的参数为`next` => 下一个中间件
chain = middlewares.map(middleware => middleware(middlewareAPI));
// 本身的dispatch放在最后执行
// dispatch仍未函数,接受的参数为`action`
// 返回的是一个高阶函数,需要注意的是中间件并不会改变原本的action
// dispatch变成了一个升级版
dispatch = compose(...chain)(store.dispatch);
return {
...store,dispatch
};
};
};
附一张图: redux-thunk
// 让action可以成为函数
function createThunkMiddleware(extraArgument) {
return ({ dispatch,getState }) => next => action => {
// action为函数类型,执行action,dispatch结束
if (typeof action === 'function') {
return action(dispatch,getState,extraArgument);
}
return next(action);
};
}
combineReducers
assertReducerSanity来验证reducer利用 combineReducers将我们所写的 export default function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {} // 有效reducer集合
// 验证reducer,必须是纯函数才有效
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
if (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 (NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
let sanityError
try {
// 检测reducer
assertReducerSanity(finalReducers)
} catch (e) {
sanityError = e
}
return function combination(state = {},action) {
if (sanityError) {
throw sanityError
}
// getUnexpectedStateShapeWarningMessage
// 检测state类型是否为0继承对象
// 用于找出多余的redcuer并给出警告
if (NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(state,finalReducers,action,unexpectedKeyCache)
if (warningMessage) {
warning(warningMessage)
}
}
let hasChanged = false
const nextState = {}
// 每次发出一个action会遍历所有的reducer
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
// 保留之前的state与新生成的state做对比
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const next StateForKey = reducer(previousStateForKey,action)
// state为undefined抛出异常
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key,action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
// 比较是否数据发生变化
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
// 未发生变化返回之前的数据
return hasChanged ? nextState : state
}
}
bindActionCreators这个基本上的作用不大,唯一运用的情况就是将其作为 function bindActionCreator(actionCreator,dispatch) {
return (...args) => dispatch(actionCreator(...args))
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby-on-rails – Rails:为什么“has_many …,… through
- ruby – 如何调试被忽略的插件?
- apt-get 依赖版本过高(Depends: g++-4.6(>= 4.6.3-1)but i
- c# – 列表Xamarin表单中的重叠元素
- 利用Flare3D 和Stage3D创建3D Flash游戏[转adobe开发中心]
- postgresql – txid_current()如何工作?
- LayaAir引擎学习日志7----AS3语言中FlashDevelop中显示文本
- 正则表达式
- React Native——AppRegistry
- Ruby数学运算符可以存储在哈希中并稍后动态应用吗?