内容简介:在redux的流程中,会存在一些特殊的需求,比如打印action的信息来进行调试,或者要处理一个异步请求。中间键就是为了处理这些特殊的需求而存在的。在redux的流程中,action creator 和 reducer 都是纯函数,action creator返回一个包含type和payload的对象,reducer函数用来处理和返回state,应该保证他们的单一性和纯度。所以能够处理这些特殊需求的只剩下dispatch了,redux的中间键就是用来对dispatch进行增强的。在使用createStor
redux中间键的作用
在redux的流程中,会存在一些特殊的需求,比如打印action的信息来进行调试,或者要处理一个异步请求。中间键就是为了处理这些特殊的需求而存在的。在redux的流程中,action creator 和 reducer 都是纯函数,action creator返回一个包含type和payload的对象,reducer函数用来处理和返回state,应该保证他们的单一性和纯度。所以能够处理这些特殊需求的只剩下dispatch了,redux的中间键就是用来对dispatch进行增强的。
一个简单的初始化
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import promise from 'redux-promise'; import logger from 'redux-logger'; import rootReducer from '../reducers'; export default function configureStore() { return createStore( rootReducer, applyMiddleware(thunk, promise, logger), ); }复制代码
在使用createStore进行初始化的时候,如果第三个参数不为空,或者第二参数为一个函数,那么就用这个enhancer函数进行初始化。createStore会被当成enhancer函数的参数传入,并在enhancer这个函数再次使用createStore对redux进行初始化。
applyMiddleware.js
import compose from './compose'; export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }复制代码
createStore是初始化传进来的,…args是初始化用的reducers和preloadedState,最终生成store对象。
在函数内部定义一个dispatch函数,定义一个middlewareAPI对象,将原生的getState和自定义的dispatch赋值给它。
middlewares.map将middlewareAPI这个对象送到每个中间键中,使得每个中间键都能通过getState访问到整个store上的数据,并且通过闭包将自定的dispatch函数传到每个中间键中,使得最终加强过的dispatch函数能被每个中间键调用。
compose函数用来对中间键数组chain进行处理,生成最终的dispatch函数。
compose.js
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))) }复制代码
上面就是compose函数,通过数组的reduce函数,将中间键进行合并。
compose([f, g, h]) ===> (...args) => f(g(h(...args)))
compose函数可以简化为上面的函数,在本文中,引入了三个中间键,下面将用这三个中间键进行简单的说明。
const thunk = thunk(middlewareAPI); const promise = promise(middlewareAPI); const logger = logger(middlewareAPI); const chain = [thunk, promise, logger]; compose(...chain) ↓ ↓ ↓ ↓ ↓ ↓ (...args) => thunk(promise(logger(...args))) 中间键中的next参数,用来将action传递到下一个中间键中,通过上面的转换可以看出来: thunk函数中的next等于promise(logger(..args)) promise函数中的next等于logger(...args) 最终生成的dispatch函数可以表示为: dispatch = compose(...chain)(store.dispatch) ↓ ↓ ↓ ↓ ↓ ↓ dispatch = thunk(promise(logger(store.dispatch))) 因为闭包的原因,最终生成的dispatch函数将会传入到每个中间键中。复制代码
通过上面的分析,可以看出每一个middleware中store的dispatch函数通过闭包的作用,都和compose函数最终生成的dispatch保持一致,并且原生的dispatch函数被包裹在最内层,middleware通过调用next()函数进入下一个中间键,并最终调用原生的dispatch函数实现action的分发,具体的过程如下图
如果在某一个中间键中调用了store.dispatch,那么就相当于从当前的中间键中跳出,重新执行一遍上图中的过程。如果中间键一直粗暴的执行store.dispatch而没有一个合适的状态去调用next函数,那么就会进入一个死循环中。具体的过程如下图
以reudx-promise为例
import isPromise from 'is-promise'; import { isFSA } from 'flux-standard-action'; export default function promiseMiddleware({ dispatch }) { return next => action => { if (!isFSA(action)) { return isPromise(action) ? action.then(dispatch) : next(action); } return isPromise(action.payload) ? action.payload .then(result => dispatch({ ...action, payload: result })) .catch(error => { dispatch({ ...action, payload: error, error: true }); return Promise.reject(error); }) : next(action); }; }复制代码
在redux-promise中,如果action的payload是一个promise对象,那么会在then中调用dispatch方法,此时就会跳出promise这个中间键,从最外层重新进入这个中间键链;如果action的payload是一个正常的对象,那么会执行next函数,进入下一个中间键。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MySQL必知必会
[英] Ben Forta / 刘晓霞、钟鸣 / 人民邮电出版社 / 2009-1 / 39.00元
《MySQL必知必会》MySQL是世界上最受欢迎的数据库管理系统之一。书中从介绍简单的数据检索开始,逐步深入一些复杂的内容,包括联结的使用、子查询、正则表达式和基于全文本的搜索、存储过程、游标、触发器、表约束,等等。通过重点突出的章节,条理清晰、系统而扼要地讲述了读者应该掌握的知识,使他们不经意间立刻功力大增。一起来看看 《MySQL必知必会》 这本书的介绍吧!