博客 知否知否,Redux源码竟如此意味深长(上集)

知否知否,Redux源码竟如此意味深长(上集)

   包袋鼠   发表于 2021-11-25 17:08  540  0

2018农历年余额已不足,

春节正在以肉眼可见的速度来临。

你即将面临的是

1、钱包渐瘦而你却每逢佳节胖三斤


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/bb3f4f7083316359374985f6316a5fab..jpg


2、来自七大姑八大姨直击灵魂的拷问


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/456bf0b19e85b189236b655abb8697c8..jpg


或许你已阅各类春节“反围攻”套路

但是最大的反套路,

莫过于

嘴炮不如加油鸭http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/b95a28530ee6d2510ae883c597d42577..jpg


除夕至初七,专栏停更一周

(已经没有什么可以阻止袋萌萌出去浪啦~)

年前#技本功#最后一更

(2019年2月13日复更)

且学且珍惜


-2019年第5期-


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/c7198971a7f0dab393c7b8d333f56793..jpg

本期夫子:长卿

袋鼠云 前端开发工程师


夫 子 说

https://mmbiz.qpic.cn/mmbiz_jpg/Xxm5O5TNdibjQYVywwT0UoPO0DUNFh4Z6wePwZc5ztzMa3Bmro27zZrchgQo1QbVJRLujmwabcYWxEp498LBplg/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1

元月二号欠下袋鼠云技术公号一篇关于Redux源码解读的文章,转眼月底,期间常被“债主”上门催债。由于年底项目工期比较紧,于是债务就这样被利滚利http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/e508832b30a05e4cec3a3c5993d37fc7..jpg
但是好在这段时间有点闲暇,于是赶紧把这篇文章给完成了。据说文章点赞多了可以抵扣利息,小伙们要是觉得我这篇文章还不错的话,记得帮我点赞哦!好让我早日摆脱债务,感激不尽!

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/911c27782d01c376da52ebf7a31b0897..jpg

好了,回到正题。今天打算和大家讲一讲redux的源码,通过分析源码,我个人觉得受益匪浅,借此通过这篇文章把我的一些心得体会向大家分享一下,另外需要注意一下这次分享的源码用的redux的V4.0.0版本,小伙伴在对照的时候可别搞错咯。接下来老司机可是要发车了,大家抓紧时间上车哦!

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/dbfcdc68b96a1d9ea967d1d9e4d63c6f..jpg

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/6f0695ae524798298a2efeb3b46a1015..jpg


在讲源码之前我们首先回顾一下redux是如何使用的,下面我们看一下使用demo:

 

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/5f1bedf359821f2c0d2e1adf2220007d..jpg

上面这段代码完整地展示了redux的使用(如果有小伙伴对这段代码不是很理解的话,建议先去学习redux的使用再来看这篇源码,这样更加事半功倍)。通过上段代码,我们拆分几个比较核心的点,我一一列举一下:


1. action的结构是如何的?

2. 如何去定义一个reducer?

3. combineReducers是如何整合多个reducer的?

4. createStore是如何创建一个store?

5.dispatch拿到action到底干了什么?

6. subscribe是如何监听状态发生改变的?

7. getState是如何拿到所有的状态值的?


本期先解决前三个疑问,让我们一起去源码里寻找答案!


1

action的结构是如何的?


首先得解释一下action是干嘛的,它是负责把数据从应用带到store里面,也是store的唯一数据来源,并由以下两个部分组成:

1. type  (操作类型)

2. payload (携带的数据)

为什么得有这两个?其实也很好理解,我们拿银行来类比。某天,你拿着一万块来到银行,走到柜台,人业务员第一件事肯定是问你要办啥业务,存钱?转账?还是还贷?你得把这些告诉业务员,不然业务没法给你办理业务,因此我们action就得有一个type,好让reducer知道你要干啥。当然,你办理存款或者是还款啥的,必不能少的就是毛爷爷了,payload对应的值就好比这些毛爷爷。用一个话来总结action的作用就是:告诉reducer拿着payload去做type这件事


2

如何去定义一个reducer?


上面讲action的时候,提到了reducer了,这里还是拿我上面的银行做个类比,当我们拿着钱去银行存钱,我们不可能自己去银行把银行保险柜打开,完了把钱放进去,这样是不允许的,我们得需要业务员这个中间人去帮我们做存钱这件事,而业务员所扮演的角色正好就是reducer所要担任的角色。接下来讲一下如何去定义一个reducer,其实reducer的写法并没有绝对的写法,只要符合下面几个条件都能称之为reducer:

1. 必须得是一个函数。

2. 函数接收两个参数。第一个:该reducer所负责的state。第二个:action。

3. 函数体内部可以针对不同的action的type做出响应,这里你可以if-else或者switch-case都是可以的。

4. 函数必须有返回值。当修改state了之后,必须将修改后的state返回。如果遇到未知的type则需要返回一个默认值。 


3

combineReducers是如何整合多个reducer的?


我们先看一下combineReducers传入的参数:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/43c25290f1f7d283c5262690ec8ea211..jpg


combineReducers接受的是一个参数首先得是对象,其次该对象每一个属性对应一个reducer。搞清楚combineReducers的结构之后,我们再看一下combineReducers对其做了哪些处理。


第一步:浅拷贝reducers


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/eb9c1446809f524ce5b1047912eb0cc3..jpg

 

这里定义了一个finalReducers和finalReducerKeys,分别用来拷贝reducers和其属性。先用Object.keys方法拿到reducers所有的属性,然后进行for循环,每一项可根据其属性拿到对应的reducer,并浅拷贝到finalReducers中,但是前提条件是每个reducer的类型必须是Function,不然会直接跳过不拷贝。


第二步:检测finalReducers里的每个reducer是否都有默认返回值


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/0f00010a0469dc0308636974c0a3d8d4..jpg


assertReducerShape方法主要检测两点:

1. 不能占用redux内部特有的命名空间

2. 如果遇到未知的action的类型,reducer不能返回undefined,得返回默认的值


如果传入type为 @@redux/INIT<随机值> 的action,返回undefined,说明没有对未 知的action的类型做响应,需要加默认值。如果对应type为 @@redux/INIT<随机值> 的action返回不为undefined,但是却对应type为 @@redux/PROBE_UNKNOWN_ACTION_<随机值> 返回为undefined,说明占用了 命名空间。整个逻辑相对简单,好好自己梳理一下。


第三步:返回一个函数,用于代理所有的reducer


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/e546a698c8863b9010c965d474910a9e..jpg


先对传入的state用getUnexpectedStateShapeWarningMessage做了一个异常检测,找出state里面没有对应reducer的key,并提示开发者做调整。接着我们跳到getUnexpectedStateShapeWarningMessage里,看其实现。


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/44d27c223aa0cee2adbbde1bef4de99c..jpg

 

getUnexpectedStateShapeWarningMessage接收四个参数inputState(state)、reducers(finalReducers)、action(action)、unexpectedKeyCache(unexpectedKeyCache),这里要说一下unexpectedKeyCache是上一次检测inputState得到的其里面没有对应的reducer集合里的异常key的集合。整个逻辑如下:

1. 前置条件判断,保证reducers集合不为{}以及inputState为简单对象

2. 找出inputState里有的key但是 reducers集合里没有key

3. 如果是替换reducer的action,跳过第四步,不打印异常信息

4. 将所有异常的key打印出来

getUnexpectedStateShapeWarningMessage分析完之后,我们接着看后面的代码。


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/8f70cdf840e221a73d48ba4b5bcdca5f..jpg


首先定义了一个hasChanged变量用来表示state是否发生变化,遍历reducers集合,将每个reducer对应的原state传入其中,得出其对应的新的state。紧接着后面对新的state做了一层未定义的校验,函数getUndefinedStateErrorMessage的代码如下:


http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/e4dd2d9d5f66684151e20616ebce533f..jpg


逻辑很简单,仅仅做了一下错误信息的拼接。未定义校验完了之后,会跟原state作对比,得出其是否发生变化。最后发生变化返回nextState,否则返回state。

0条评论
社区公告
  • 大数据领域最专业的产品&技术交流社区,专注于探讨与分享大数据领域有趣又火热的信息,专业又专注的数据人园地

最新活动更多
微信扫码获取数字化转型资料
钉钉扫码加入技术交流群