前言
Redux 是如今最流行的状态管理框架之一,其通过单一 Store 和限制状态更新的方式,让状态变得可控可预测。然而,redux 的一系列限制,也让其产生了一些弊端:
- 样板式代码过多,书写繁琐
- 不支持异步 action
那么有什么办法来让 redux 支持异步 action 呢。redux 吸收借鉴了 express 和 koa 的 middleware 思想,拥有一套强大的 middleware 系统,通过 middleware,即可实现异步 action 功能。今天,闲来无事,走马观花,重新认识下 redux middleware
Middleware 的用法
先来看看,在 redux 中,它是如何使用的。
1 | import { createStore, combineReducers, applyMiddleware } from "redux"; |
很简单,使用时,只要引入 applyMiddleware 函数,然后将你需要使用的 middleware 作为参数传入 applyMiddleware 调用,最后将返回结果作为参数传入 createStore,就完成了 redux 引入 middleware
Middleware 的形式
再来看看,一个 middleware 长什么样,以 redux-thunk 这个最有名的天选 middleware 为例
1 | function createThunkMiddleware(extraArgument) { |
redux-thunk 代码就这么短短几行,为了注入 extraArgument,特意使用的工厂模式,生产最后会导出的 thunk。所以,删减下,这个 thunk middleware 其实长这样
1 | const thunk = ({ dispatch, getState }) => next => action => { |
结合文档中的其它 middleware,大致能得出一个 middleware 长什么样了
1 | ({ dispatch, getState })=> (next) => (action) => {} |
Middleware 机制的实现
查看 redux 源码中的 middleware 部分,验证下一个 middleware 是不是应该长这样,以及 redux 是如何实现 middleware 机制的。
首先看applyMiddleware.js
文件
1 | export default function applyMiddleware(...middlewares) { |
applyMiddleware 是一个高阶函数,利用 ES6 rest 操作符,
将传入的 middleware,收集到一个 middlewares 数组中,然后返回一个新的函数。而这个新的函数则是一个store enhancer, 一个 store enhancer, 接收一个 store creator,返回一个新的 store creator.
1 | type StoreEnhancer = (next: StoreCreator) => StoreCreator |
新的 store creator 内部,先调用旧的 store creator, 并且定义了一个默认的 dispatch。然后创建一个对象 middlewareAPI,这个对象有两个方法(getState 和 dispath), getState 为原 store.getState 的引用;dispatch 为一个箭头函数,里面会调用默认的 dispatch, 这里用箭头函数包裹,会形成一个闭包, 当默认 dispatch 函数变化的时候,middlewareAPI 中的 dispatch 也会变化。
然后 middlewares.map 一下,执行各个 middleware,为它们注入 middlewareAPI 这个对象,返回新的名叫 chain 的数组。
看到这里,也就知道了,为什么一个中间件会
1 | ({ dispatch, getState } )=> {} |
接下来,调用了一个 compose 函数.
1 | export default function compose(...funcs) { |
compose 函数通过 rest 将参数收集到一个数组中,然后调用 reduce 这个累计函数,返回一个新的函数。如:
1 | compose(f, g, h), 返回(...args) => f(g(h(...args))) |
所以,chain 数组中的函数,就实现了如下的调用
1 | const a = (next) => (action) => {}; |
而这就是 redux middleware 的本质,包装原 dispatch, 返回一个新的 dispatch.
结语
走马观花,简单对 Middleware 的用法,形式,实现进行了一瞥,Middleware 简单而又强大,里面蕴含了函数柯里化的思想; 闭包和 ES5 reduce 函数的使用更是巧妙。水下此文,已备忘。