redux
是什么、有什么作用,解决什么问题,如果你还不知道,请先去这里:
下面的文章适合对redux有一定理解和使用经验的人
项目github地址:
如果你觉得对你有帮助的话记得给我一个star呢
applyMiddleware有什么用:
使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。
Middleware 可以让你
同时, middleware 还拥有“可组合”这一关键特性。多个 middleware 可以被组合到一起使用,形成 middleware 链。
其中标红色的部分是我们很常用到的,例如redux-thunk
、redux-promise
插件。
若要很好的理解applyMiddleware
我们纳入redux-thunk
源码来分析:
先看看 applyMiddleware的源码:
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { const store = createStore(reducer, preloadedState, enhancer) let dispatch = store.dispatch let chain = [] const middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } }}复制代码
非常的简洁,整体含义就是:applyMiddleware 接收多个参数,并返回一个以createStore为参数的function,此function经过一系列的处理之后返回了 createStore里面的所有方法和重写的dispatch。
这里还是不能很好理解的话我们来看看redux-thunk
的源码:
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); };}const thunk = createThunkMiddleware();thunk.withExtraArgument = createThunkMiddleware;export default thunk;复制代码
也是非常的简洁接收一个extraArgument参数,返回一个{ dispatch, getState }为参数的function,即最终返回的是这个函数:
从源码中可以看出 thunk 最终的值为 这个function({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); };复制代码
让我们来简化一下它用通俗的方式改写如下,
//用通俗的代码重写let AAA = function (opt) { var dispatch = opt.dispatch, getState = opt.getState; return function (next) { return function (action) { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; };};复制代码
可以很清晰的看出,传入了dispatch和getState,返回了一个函数,并判断函数的action参数是否为function做不同的处理,其中标识为红色的为实现异步的核心。
也许还是不能理解所以然,下面让我们来理清它。
来看看createStore,applyMiddleware 加上 redux-thunk 之后的调用方式:
import thunk from 'redux-thunk'import { createStore,applyMiddleware } from './redux'const store = createStore( reducers, applyMiddleware(thunk))复制代码
我们来给一个reducers测试案例来分析源码的走向,完整代码如下:
import thunk from 'redux-thunk'import { createStore,applyMiddleware } from './redux'const ADD_TODO = 'ADD_TODO'function reducers(state = [], action) { switch (action.type) { case 'ADD_TODO': return state.concat([ action.text ]) default: return state }}// 创建 Redux 的 store 对象const store = createStore( reducers, applyMiddleware(thunk))console.log(store.getState())复制代码
下面我通过在代码中注释的方式来说明运行流程:
//此时 ...middlewares = [ AAA ] AAA在上面有说明export default function applyMiddleware(...middlewares) { //返回一个函数 唯一的参数为 createStore,也就是redux中的createStore函数 return (createStore) => (reducer, preloadedState, enhancer) => { //这里相执行了createStore方法 传了3个参数, //这三个参数从createStore.js 中的 return enhancer(createStore)(reducer, preloadedState) 得来,可以看出传来的参数只有2个 //因此也就不会再执行createStore.js中的 enhancer函数 const store = createStore(reducer, preloadedState, enhancer) //这里得到了store,拿取createStore.js 中的dispatch函数 存储在dispatch临时变量中 let dispatch = store.dispatch //因为 ...middlewares 是一个数组,临时存储 let chain = [] //包装 getState 和 dispatch 两个方法 const middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } /* 循环调用 体现在案例中时 middlewares 的值为 [AAA] 因此运行一次 返回的chain为 [ AAA(middlewareAPI) ], 可以看出middlewareAPI值正是AAA函数需要的两个参数 体现在案例中此时 chain 值为: [ function (next) { return function (action) { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; }, ] */ chain = middlewares.map(middleware => middleware(middlewareAPI)) /* 这段代码运行完之后会得到新的dispatch 体现在案例中下面这段代码返回值dispatch为: function (action) { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return store.dispatch(action); }; 这里的面的 next 值为 store.dispatch */ dispatch = compose(...chain)(store.dispatch) //最终返回新的createStore方法,重写了dispatch,其他的都没有变 return { ...store, dispatch } }}复制代码
根据以上的分析我们来给一个异步的actions案例,并dispatch调用:
function actions(){ return (dispatch)=>{ dispatch({ type: ADD_TODO, text: 'Read the docs' }) }}//使用redux-think处理之后的dispatch触发actionsstore.dispatch(actions())复制代码
根据以上的分析我们知道最终处理之后返回的dispatch
值为:
function (action) { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return store.dispatch(action);};复制代码
当调用actions()之后我们可以明显的看出 typeof action === 'function' 为真
因此走是return action(dispatch, getState, extraArgument);
,再去触发reducers函数 最终通过 currentState = currentReducer(currentState, action)
从而改变唯一的store状态数据
经过以上的分析就能很好的理解alpplyMiddleware
这个方法和redux-thunk
的主要作用了。
接下来我们进入到redux的最后一个方法 bindActionCreators
关注我的博客:
原文地址: