Redux学习之解读applyMiddleware源码深入middleware工作机制

在上一周的学习中,我们熟悉了通过如何通过redux去管理数据,而在这一节中,我们将深入到redux的知识中学习。

首先谈一谈为什么要用到middleware

我们知道在一个简单的数据流场景中,点击一个button后,在回调中分发一个action,reducer收到action后就会更新state并通知view重新渲染,如下图所示

Redux学习之解读applyMiddleware源码深入middleware工作机制

但是如果需要打印每一个action来调试,就得去改dispatch或者reducer实现,使其具备打印功能,那么该如何做?因此,需要中间件的加入。

Redux学习之解读applyMiddleware源码深入middleware工作机制

上图展示了应用middleware后的Redux处理事件的逻辑,每个middleware都可以处理一个相对独立的事物,通过串联不同的middleware实现变化多样的功能!

小结:Redux中的reducer更加的专注于转化逻辑,所以middleware是为了增强dispatch而出现的。 middleware是如何工作的

Redux提供了一个applyMiddleware方法来加载middleware,它的源码是这样的:

import compose from './compose'; export default function applyMiddleware(...middlewares) { return (next) => (reducer, initalState) => { let store = next(reducer, initalState); let dispatch = store.dispatch; let chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map( middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch }; } }

然后我们再上一个logger middleware的源码实现:

export default store => next => action => { console.log('dispatch:', action); next(action); console.log('finish:', action); }

虽然看到“源码”的那两个字的时候,内心一万只草什么马奔过,但是一看到代码这么精简,这么优美,那就初读一下源码把。
然后

Redux学习之解读applyMiddleware源码深入middleware工作机制

接下来就开始解读上面源码

深入解析middleware运行原理 1. 函数式编程思想设计 middleware是一个层层包裹的匿名函数,这其实是函数式编程的currying(Currying就是把一个带有多个参数的函数拆分成一系列带部分参数的函数)。那么applyMiddleware会对logger这个middleware进行层层的调用,动态的将store和next参数赋值。 那么currying的middleware结构有什么好处呢? 1.1 易串联: currying函数具有延迟执行的特性,通过不断currying形成的middleware可以积累参数,再配合组合(compose)的方式,这样很容易就形成pipeline来处理数据流 1.2 共享store:在applyMiddleware执行的过程当中,store还是旧的,但是因为闭包的存在,applyMiddleware完成之后,所有的middleware内部拿到的store是最新的且是相同的。 并且applyMiddleware的结构也是一个多层currying的函数,借助compose,applyMiddleware可以用来和其他插件加强createStore函数 2. 给middleware分发store 通过如下方式创建一个普通的store ``` let newStore = applyMiddleware(mid1, mid2, mid3, ...)(createStore)(reducer, null); ``` 上述代码执行完后,applyMiddleware方法陆续获得了3个参数,第一个是middlewares数组[mid1, mid2, mid3,...],第二个是Redux原生的createStore方法,最后一个是reducer。然后我们可以看到applyMiddleware利用createStore和reducer创建了一个store。而store的getState方法和dispatch方法又分别被直接和间接地赋值给middlewareAPI变量的store ``` const middleAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middle => middleware(middlewareAPI)) ``` 然后,每个middleware带着middlewareAPI这个参数分别执行一遍,执行后,得到一个chain数组[f1, f2, ..., fx, ..., fn],它保存的对象是第二个箭头函数返回的匿名函数。因为是闭包,每个匿名函数多可以访问相同的store,即middlewareAPI. 3.组合串联middleware 这一层只有一行代码,确是applyMiddleware精华所在。 ``` dispatch = compose(...chain)(store.dispatch); ``` 其中,compose是函数式编程中的组合,它将chain中的所有匿名函数[f1, f2, ..., fn]组装成一个新的函数,即新的dispatch。当新的dispatch执行的时候,[f1, f2, ...]会从右到左依次执行。Redux中compose的实现是这样的,当然实现的方式不唯一。 ``` function compose(...funs) { return arg => funcs.reduceRight( (compose, f) => f(composed), arg) } ``` compose(...funcs)返回的是一个匿名函数,其中funcs就是chain数组。当调用reduceRight时,依次从funcs数组的右端取一个函数f(x)拿来执行,f(x)的参数composed就是前一次f(x+1)执行的结果,而第一次执行的f(n)n代表chain的长度,它的参数arg就是store.dispatch。 因此,当compose执行完后,我们得到的dispatch是这样的: 假设n=3: dispatch = f1(f2(f3(store.dispatch))); 这时调用dispatch,每一个middleware就会依次执行了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwzxd.html