但是之前在看官方文件的时候,middleware的地方没有完全看懂,看到后面就雾煞煞了
这次重看了一遍官方文件讲middleware跟非同步操作的地方,边看边做笔记,总算是把middleware的实作原理弄懂了
依照惯例分享一下心得
官方文件很棒的点就是这篇不只教你怎么用,还从头讲起,让你知道为什么会是现在这样的形式。
正文
你在看了某些教学文章之后觉得redux实在是太棒了,于是开始采用redux做自己的产品
可是此时此刻你突然想要做一个功能:logging,你想记录每个action,以及执行action完以后store的改变
该怎么做呢?先从最简单的方法开始吧!
第一次尝试:最直觉的方法
假设我们原本dispatch action的code是这样写
我们可以直接改成
第二次尝试:包成函式
但是第一种方法大家都知道不能这样,因为程式里面一定不只一个地方需要做这件事情
那接下来怎么办呢?把它包成函式吧
可是这样子,你每个需要dispatch的地方都要import这个函式,有没有更好的做法呢?
第三次尝试:Monkeypatching
什么是?大家可以自己估摸一下
大意就是:在runtime的时候把某个东西换掉
就像是你可以在你的chrome devtool里面写
这样子原本会在console里面出现的讯息,就会全部用alert显示了那用在这里我们要怎么用呢?
这样子的话,原本的code完全不用更动,你只要在程式刚开始的地方把换掉就好了
实在是轻松又愉快,但是我们很快就碰到了一个新的问题
如果我现在想要一个错误回报的机制怎么办?当dispatch出错的时候,我想把错误传回server
嗯…好问题
我们可以把这两个想做的事情独立成两个function,差不多像是这样
刚开始读到这段的时候我就有点晕了,不太懂为什么这样子可以
后面的不是会把前面的覆盖掉吗?后来再看几次终于看懂,精髓就在于那个
上面code的行为大概会是这样:
执行第一个函式
现在的(redux真正发送action的函式)被保存起来
被换掉,换成这个函式,这个函式的行为会是:做记录并且呼叫原本的dispatch
执行第二个函式`patchStoreToAddCrashReporting(store);``
现在的dispatch(注意,已经变成dispatchAndLog这个函式了)被保存起来
被换掉,换成这个函式,这个函式的行为会是:做记录并且呼叫原本的dispatc
好,接着若是我们呼叫,看一下流程会怎么走
因为刚刚被换掉,所以执行
执行,而就是之前保存的dispatch,就是
执行
做记录,然后执行,而就是之前保存的dispatch,就是最原始的dispatch
执行最原始的dispatch,执行完毕以后跳回这个function
回到,印出改变后的state
回到,因为都没有错误,所以不做任何事
结束
这样子就达成我们middleware最重要的功能,可以让action经过一层又一层的中间件,最后抵达store
但是这样子还是不够好
第四次尝试:把Monkeypatching藏起来
之前我们都是直接把换掉,那如果我们不要直接换掉,而是传回一个function,会发生什么事?
假设我们的也改成这种形式,那我们就可以
其实只是把抽出来,独立在function外面而已但这样做的好处就是,我们可以这样
但是这样子其实只是把monkeypatch的地方抽出来而已,实际上还是在下一步,我们要把monkeypatch这个方法彻底移除掉
第五次尝试:把monkeypatching移除掉
为什么我们要override ?
有一个很重要的因素就是,这样才能不断呼叫之前的
如果少了那重要的一行,那就无法达成chaining的效果
但其实除了这样子写,我们还有另外一个方法可以用
我们可以接收一个next的参数,达到相同目的
官方文件接着有点讲太快了,咻咻咻就直接把最重要的一个部分讲完
我这边试着把进度放慢,讲更多细节的东西,其实就是差在currying这个概念
继续刚刚讲的,我们可以接收一个next的参数,就会变成这样
可以看到跟之前长得很像,只是原本的next是放在里面,现在变成参数传进来
那我们在使用的时候就变成
差别在于函式里面的被拿掉了
我们的middleware函式跟变得更干净了点
改成这样之后,把我们原本的也改掉,让它符合新的写法
接着我们回来看官方给的文件跟范例,跟现在我们写的有哪边不一样
第一个点是,跟我们是传入两个参数,但是官方的实现只传入了一个
用了一种叫做的技巧
什么是?就是把多个参数的函数切成很多只有一个参数的函数直接看范例比较了解:
有了基本概念以后,就可以把我们刚刚的函式也做这样的改变
在我当初看官方文件的时候,最困扰我的就是这一段
因为之前很少用这种回传function又回传function的写法所以一下子被弄得头昏眼花
于是只好先找出不要那么多层函数的方法,然后了解之后再去了解原本的code
对我来说这样子会比较容易啦,不然一下子跳太快
applyMiddleware就可以改成这样
其实做到这边,就已经跟本身的实现有个八分像了
事实上middleware的写法其实就是要求的写法
最后来看一下官方提供的用法要怎么用
总结
在看官方文件的时候,一直到前面都还看得懂,只是一下突然跳到currying那边
后来下定决心一定要看懂,重新看一次之后,一行一行去理解是什么意思、流程怎么跑之后就比较清楚了
这边大幅度参考官方范例,code也是直接抄来的,只是有做了一点小改变所以在这边说明
像是官方范例的applyMiddleware里面,其实前面都有
是因为执行顺序的关系,是复制这个array但是为什么要复制我就不知道了,是因为不要改到原本的参数吗?
总之,希望这篇文章能帮助到一些初学者
最后还是要推荐大家去看官方文件
如果有哪边写错,还麻烦留言,感谢大家
领取专属 10元无门槛券
私享最新 技术干货