聊一聊Redux中间件机制
Posted 前端纪元
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊一聊Redux中间件机制相关的知识,希望对你有一定的参考价值。
前言
Redux的基本做法是:用户发出action,reducer函数计算出新的state值,view重新渲染页面。那么如果我想在这过程中添加一些自定义处理,该在哪里添加呢?
action?action只是存放数据的一个普通对象,只能被别人操作。
reducer?reducer是纯函数,只用来计算state的值。
view?view只是state的视觉展示
那么在哪里进行处理? 只能在将action发送到reducer处理的这个过程里,也就是store.dispatch()这一步。即文档里所描述的中间件是位于 action 被发起之后,到达 reducer 之前的扩展点。
中间件实现
如果要把对每一次state处理的前后状态进行log记录的话,我们可以怎么做?
1.0,封装dispatch
export default logger = (store) =>(store, action) {
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
}
// 然后用它替换 store.dispatch()
logger(store, addTodo('Use Redux'))
但是每次导入方法,烦的嘞。。。
2.0,替换dispatch:
export default logger = (store) => {
const next = store.dispatch
store.dispatch = function dispatchWithLog(action) {
console.log('pre state',store.getState())
console.log('do action',action)
let result = next(action)
console.log('next state',store.getState())
return result;
}
}
3.0,直接返回新的dispatch:
export default logger = (store)=> {
const next = store.dispatch
return function(action) {
console.log('pre state',store.getState())
console.log('do action',action)
let result = next(action)
console.log('next state',store.getState())
return result;
}
}
// 同时在myApplyMiddleware方法中提供一个将上述返回函数运用起来的方法
function myApplyMiddleware(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
middlewares.forEach(middleware => {
store.dispatch = middleware(store)
})
}
然后这样使用:
myApplyMiddleware(store, [logger,...])
为什么要返回新的dispatch?因为后续直接调用它,同时更关键的是避免后续中间件还使用了初始的dispatch函数,即每个中间件所用到的dispatch都是前一个中间件处理过的dispatch。
4.0, ES6 柯里化
export default logger = store => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
myApplyMiddleware方法
更新我们的myApplyMiddleware方法,在这里我们取得最终被重重处理过的dispatch函数,并返回一个store副本:
function myApplyMiddleware(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
let dispatch = store.dispatch
middlewares.forEach(middleware => (
dispatch = middleware(store)(dispatch))
)
return Object.assign({}, store, { dispatch })
}
Redux中多个中间件执行顺序是怎么样的?洋葱壳模型
做了个试验:
const logger1 = store => next => action => {
console.log('middleware111 start')
let result = next(action)
console.log('middleware111 end')
return result
}
const logger2 = store => next => action => {
console.log('middleware222 start')
let result = next(action)
console.log('middleware222 end')
return result
}
const logger3 = store => next => action => {
console.log('middleware333 start')
let result = next(action)
console.log('middleware333 end')
return result
}
let store = createStore(TodoApp,
applyMiddleware(logger1,logger2,logger3)
)
结果如图:
那么如果我在某个中间件里又dispatch了action呢?
在中间件中,调用 dispatch 发送其他Action, 会递归先处理新发出的 Action, 所以这时候 next(action) 写在哪里就很重要了。
如果 reducer 执行时,需要依赖新发出的 Action 对状态的改变, 那就要在 next(action) 前面 dispatch 发出新的 Action。
如果 dispatch 新的 Action 需要依赖于本次处理的 Action 对状态的改变,那就要在 next(action) 后面 dispatch 发出新的 Action, 这种情况更常见一些。
常用的redux中间件
redux-logger
redux-thunk
redux-promise
redux-actions
以上是关于聊一聊Redux中间件机制的主要内容,如果未能解决你的问题,请参考以下文章