redux源码解读(二)
之前,已经写过一篇redux源码解读(一),主要分析了 redux
的核心思想,并用100多行代码实现一个简单的 redux
。但是,那个实现还不具备合并 reducer
和添加 middleware
的功能。
今天我们一起来看看合并 reducer
(即 combineReducers
) 的原理和实现。
在分析原理之前,先来看看combineReducers
的用法:
import { createStore, combineReducers } from 'redux';
const addScore = (state, action) => {};
const deleteScore = (state, action) => {};
const rootReducer = combineReducers({addStore, deleteScore});
const store = createStore(rootReducer);
从上面的例子可以看出,combineReducers
接收的参数类型是一个原生对象,其中这个对象的每个键值都是一个 reducer
纯函数。另外,因为 combineReducer()
返回的结果可以传递给createStore
作为参数,可以推出它返回的结果也是一个 reducer
函数。
了解了 combineReducer
用法之后 ,那开始一步一步的用代码来实现其功能吧。
首先,需要先声明 combineReducers
的参数,然后判断传进来的参数是不是原生对象类型( plain object
),如果不是,则抛出异常,如果是,则需要获取该对象的所有属性(key)并存放到变量 reducerKeys
里面,然后对这些key进行遍历,过滤掉那些不是函数的值,并将结果放到 finalReducerKeys
里面。代码如下:
export default function combineReducers(reducers) {
// 判断参数reducers是否为对象
if(Object.prototype.toString.call(reducer) !== '[object Object]') {
throw new Error('combineReducers expected plain object params');
}
const reducerKeys = Object.keys(reducers);
let finalReducerKeys = [];
// 过滤掉value不是Function类型的键名,然后将结果放到fianlReducerKeys里面
reducerKeys.forEach((key, i) => {
if(typeof reducers[key] === 'function') {
finalReducerKeys.push(key);
}
});
}
前面已经提到过了 combineReducers
返回的结果是一个纯函数。那这个返回的函数需要处理些什么逻辑呢?因为他合并了其他的 reducers
,所以需要遍历这些 reducer
并执行他们。然后,并对比一下执行 reducer
之后的数据有没有变化 ,如果有变化则返回新的 state
, 否则直接返回之前的 state
。代码如下:
export default function combineReducers(reducers) {
// 省略和前面相同的部分
// 返回一个新的、经过组合的reducer函数
return function(state = {}, action) {
let hasChanged = false;
const nextState = {};
// 遍历finalReducerKeys,并调用对应的reducer。
finalReducerKeys.forEach((key, i) => {
const stateForKey = state[key];
const nextStateForKey = reducers[key](stateForKey, action);
nextState[key] = nextStateForKey;
// 如果前后状态不一样,则hasChanged设为true
if(stateForKey !== nextStateForKey) {
hasChanged = true;
}
});
// 如果有变化,则返回新的state,否则返回旧的
return hasChanged ? nextState : state;
}
}
OK,《redux
源码解读(二)》就写到这里,今天周五啦,祝大家周末愉快哈!如果对 combineReducer
还有不明白的地方,欢迎留言讨论哈。另外,可能有些地方我分析得不到位的,建议到我的github去下载代码自己再好好研究一下。重要的事情说三遍:代码在这里下载! 代码在这里下载! 代码在这里下载!
redux源码解读(二)的更多相关文章
- Redux 源码解读 —— 从源码开始学 Redux
已经快一年没有碰过 React 全家桶了,最近换了个项目组要用到 React 技术栈,所以最近又复习了一下:捡起旧知识的同时又有了一些新的收获,在这里作文以记之. 在阅读文章之前,最好已经知道如何使用 ...
- jQuery.Callbacks 源码解读二
一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...
- redux源码解读(一)
redux 的源码虽然代码量并不多(除去注释大概300行吧).但是,因为函数式编程的思想在里面体现得淋漓尽致,理解起来并不太容易,所以准备使用三篇文章来分析. 第一篇,主要研究 redux 的核心思想 ...
- redux源码解读
react在做大型项目的时候,前端的数据一般会越来越复杂,状态的变化难以跟踪.无法预测,而redux可以很好的结合react使用,保证数据的单向流动,可以很好的管理整个项目的状态,但是具体来说,下面是 ...
- (转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
转自:http://www.baiyuxiong.com/?p=886 ---------------------------------------------------------------- ...
- 手把手教你撸一套Redux(Redux源码解读)
Redux 版本:3.7.2 Redux 是 JavaScript 状态容器,提供可预测化的状态管理. 说白了Redux就是一个数据存储工具,所以数据基础模型有get方法,set方法以及数据改变后通知 ...
- mybatis源码解读(二)——构建Configuration对象
Configuration 对象保存了所有mybatis的配置信息,主要包括: ①. mybatis-configuration.xml 基础配置文件 ②. mapper.xml 映射器配置文件 1. ...
- ConcurrentHashMap源码解读二
接下来就讲解put里面的三个方法,分别是 1.数组初始化方法initTable() 2.线程协助扩容方法helpTransfer() 3.计数方法addCount() 首先是数组初始化,再将源码之前, ...
- go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
nsqlookupd: 官方文档解释见:http://bitly.github.io/nsq/components/nsqlookupd.html 用官方话来讲是:nsqlookupd管理拓扑信息,客 ...
随机推荐
- ecplise导入项目报错而文件不报错
第一步 确认项目的jdk和tomcat版本,在Java Build Path的Libraries中查看包是否有报错,按照本机环境进行配置 第二步 检查 Java Compiler中的jdk版本,和ec ...
- Git问题总结
1 git push origin master 提示Everything up-to-date 表示本地仓库和远程仓库是一致的,没有更新,需要检查自己的提交. 2 git push origin m ...
- JSP学习(1)---JSP基本原理
一.JSP的本质 其本质是Servlet,web应用中的每个jsp页面都会由servlet容器生成对应的servlet. 在tomcat中,jsp生成的servlet在work文件夹下: 原jsp文件 ...
- 基于uniGui开发的Delphi后台管理框架uniFramework
uniGui是基于Delphi的一套开发Web应用的UI框架,前端使用的是ExtJS,最新版的uniGUI1.5 1480已支持新版的ExtJS6.5.3.我认为uniGUI是目前Delphi下最完善 ...
- css设置垂直居中方式总结
方式1:flex布局,display:flex;align-items:center <!DOCTYPE html> <html lang="en"> &l ...
- windows 下安装MySQL 服务无法启动类问题
解决方案: 1 执行 mysqld.exe -nt remove 2 执行 mysqld --initialize(中间是两个中划线) 3 执行 mysqld.exe -nt install 4 执行 ...
- vi编辑器之删除操作
参见 1.vi列删除 方法一: ctrl+v进入列编辑模式: 将光标定位子想要删除的起始列: 移动光标至结束列(直接通过移动光标选中,对列不对齐时,可能比较长的行,无法全部选中,尤其是需要一直删除到行 ...
- 转载 * jQuery实现动态分割div—通过拖动分隔栏实现上下、左右动态改变左右、上下两个相邻div的大小
由jQuery实现上下.左右动态改变左右.上下两个div的大小,需要自己引入jquery1.8.0.min.js包 可用于页面布局. //============================ind ...
- pycharm安装pip报错的处理办法
这几天在用pycharm的时候,发现安装软件的时候报 module 'pip' has no attribute 'main' ,后来综合网上的办法以及分析错误提示,原因是在于pycharm安装目录下 ...
- day 15递归 匿名函数
三元表达式 目的是简化书写 局限性:三元表达式智能简化仅有两个分支的if判断,而且这个判断无论是否成立都必须要返回值 res = True if age >=18 else False 递归: ...