事实上,程序员是个很“懒”的物种,总是想着怎么还能更简洁一点,怎么还能更简化一下代码。脑子里整天在琢磨这些事情,也正是这种“懒”的思想才催生出了发展。当然也不全是“懒”,更多的是为了少出错,多干活。因为redux的野心本来就不小,它的诞生就是为了管理状态的,并不区分什么库或者框架使用。
- 听说可以偷懒我当然愿意来学学啊,为了减轻工作负担嘛!
其实再整个使用redux的过程中我们会发现我们有很多的动作(代码)和逻辑是可以复用的。当然程序员也为复用代码而不断努力着。那么,下面我们来看看那些东西在redux中时刻一而再再而三的简化复用的呢?!
- 随着项目的变大我们会将redux也会拆的更细。便于分组件管理。但是一个屋项目只有一个仓库,所以这样一来我们就涉及到要做出合并。
- redux/index.js
import createStore from './createStore';
import bindActionCreators from './bindActionCreators';
import combineReducers from './combineReducers';
import compose from './compose';
import applyMiddleware from './applyMiddleware';
export {
createStore,
bindActionCreators,
combineReducers,
compose,
applyMiddleware
}
- reudx/createStore.js
- 其实这里的创建仓库和之前的并没有什么不一样我就不再多赘述了直接看上一篇:摹写简版redux
export default function createStore(reducers, initState) {
// todo same things
}
<!--不过要去掉上一篇里面的reducer本来也只是拿来做个试验而已,不属于createStore的正式代码。-->
- redux/bindActionCreators.js
看名字应该也差不多知道这个是干什么的了,是的你猜的没错他就是用来合并actions的,这么说好像不太贴切。实际上是用来绑定的
export default function (actionCreators, dispatch) {
let boundActionCreators = {};
<!--这步是把actions文件夹下的所有组件的action合并起来的操作-->
for(let key in actionCreators) {
<!--高阶函数因为有可能还会传入参数,或者加其他逻辑,AOP切片-->
boundActionCreators[key] = function(...args) {
reutrn dispatch(actionCreators[key](...args))
}
}
return boundActionCreators;
}
-redux/combineReducers.js
这个是对reducers文件夹下的reducer进行合并的文件一般会在reducers文件夹下写一个index.js的文件用来合并。
export default function(reducers) {
reutrn functoin(state = {}, action) {
let nextStates = {};
for (let key in reducers){
<!--取出每个key对应的reducer-->
let reducer = reducers[key];
<!--取出每个key对应的状态-->
let prevState = state[key];
<!--根据action和每个key对应的状态,计算出每个key对应的下一个状态-->
let nextState = reducer(prevState, action);
<!--然后用nextStates收集起来-->
nextStates[key] = nextState;
}
return nextStates;
}
}
- redux/applyMiddleware.js
神奇的中间件来了,也是最烧脑的一部分。无限制闭包高阶函数,一不小心就有可能跑偏。
import compose from './compose';
export default function applyMiddleware(...middlewares) {
return function(createStore) {
return function(reducer) {
let store = createStore(reducer);
let dispatch;
middlewareParams = {
getState: store.getState,
dispatch: a=>dispatch(a)
}
let middlwareChain = middlewares.map(middleware => middleware(middlewareParams));
dispatch = compose(...middlewareChain)(store.dispatch);
return {
..store,
dispatch
}
}
}
};
- redux/compose.js
这里补一下compose文件,功能很简单,理解起来可能并不那么简单。
export default function compose(...middlewares) {
if(middlewares.length === 0) return () =>{};
if(middlewares.length === 1) return middlewares[0];
return middlewares.reduce((memo, cur) => function(...args) {
memo = memo(cur(...args));
return memo;
})
}
<!--简单实现一下数组的reduce方法,便于理解-->
Array.prototype.reduce = function(fn, init) {
for res = init;
for(let i= 0; i < this.length; i++) {
res = fn(res,this[i]);
}
return res
}
针对中间件我还是给个例子说明一下
- 不同的中间件虽然业务不一样,功能不一样,但是它的签名是一样的,代码结构是一样的
- dispatch类似于store.dispatch用来派发动作
- getState类似于store.getState()用来获取最新的仓库状态
- 比如说现在有一个需求number初始值=100当我点击-号的时候,让number向下减,减至0停下来
- 为什么不能是store.dispatch,而需要最终重写后的dispatch,是为了让我们在中间件里可以重头再来,重新派发
- 所有的中间件的形式都一样
import {createStore,apllyMiddleware} from 'redux'
import reduce from '....'
function logger({dispatch, getState}) {
<!--next代表的是调用下一个中间件或者原来的store.dispatch-->
return function(next) {
<!--以下返回的这个匿名函数就是重写后的dispatch方法-->
return function(action) {
console.log('old state', getState());
<!--调用原来的store.dispatch方法派发action-->
next(action);
console.log('new state', getState());
}
}
}
<!--thunk中间件可以派发一个函数-->
function thunk({dispatch, getState}) {
return function(next) {
return function(action) {
if(typeof action === 'function') {
action(dispatch, getState);
} else {
next(action);
}
}
}
}
<!--promise中间件可以派发一个promise函数-->
function promise() {
return function(next) {
return function(action) {
if(action.then && typeof action.then === 'function') {
action.then(dispatch);
} else {
next(action);
}
}
}
}
store = applyMiddleware(promise, thunk, logger)(createStore)(reduce);
export default store