Redux之combineReducers(reducers)详解
大家好,最近有点忙,忙什么呢?忙着学习一个新的框架Redux,那么这个框架主要是用来做什么的,这篇博客暂时不做介绍,这篇博客针对有一定Redux开发基础的人员,所以今天我讲的重点是Redux里面很重要的一个方法-combineReducers(reducers)。
(一)官网介绍
首先,按照惯例,这个方法是什么,干什么用,输入是什么,输出是什么,这些都是我们要了解的,所以我们先来看看官网是如何介绍它的,在后面的内容中我会给大家分析一下这个方法内部是如何实现的以及它的实现原理,慢慢来,不要慌~
combineReducers(reducers)
这里为了方便大家阅读,直接上中文解释
随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分。
combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。
合并后的 reducer 可以调用各个子 reducer,并把它们的结果合并成一个 state 对象。state 对象的结构由传入的多个 reducer 的 key 决定。
最终,state 对象的结构会是这样的:
- {
- reducer1: ...
- reducer2: ...
- }
通过为传入对象的 reducer 命名不同来控制 state key 的命名。例如,你可以调用 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) 将 state 结构变为 { todos, counter }。
通常的做法是命名 reducer,然后 state 再去分割那些信息,因此你可以使用 ES6 的简写方法:combineReducers({ counter, todos })。这与 combineReducers({ counter: counter, todos: todos }) 一样。
Flux 用户使用须知
本函数可以帮助你组织多个 reducer,使它们分别管理自身相关联的 state。类似于 Flux 中的多个 store 分别管理不同的 state。在 Redux 中,只有一个 store,但是 combineReducers 让你拥有多个 reducer,同时保持各自负责逻辑块的独立性。
参数
reducers (Object): 一个对象,它的值(value) 对应不同的 reducer 函数,这些 reducer 函数后面会被合并成一个。下面会介绍传入 reducer 函数需要满足的规则。
之前的文档曾建议使用 ES6 的 import * as reducers 语法来获得 reducer 对象。这一点造成了很多疑问,因此现在建议在 reducers/index.js 里使用 combineReducers() 来对外输出一个 reducer。下面有示例说明。
返回值
(Function):一个调用 reducers 对象里所有 reducer 的 reducer,并且构造一个与 reducers 对象结构相同的 state 对象。
注意
本函数设计的时候有点偏主观,就是为了避免新手犯一些常见错误。也因些我们故意设定一些规则,但如果你自己手动编写根 redcuer 时并不需要遵守这些规则。
每个传入 combineReducers 的 reducer 都需满足以下规则:
所有未匹配到的 action,必须把它接收到的第一个参数也就是那个 state 原封不动返回。
永远不能返回 undefined。当过早 return 时非常容易犯这个错误,为了避免错误扩散,遇到这种情况时 combineReducers 会抛异常。
如果传入的 state 就是 undefined,一定要返回对应 reducer 的初始 state。根据上一条规则,初始 state 禁止使用 undefined。使用 ES6 的默认参数值语法来设置初始 state 很容易,但你也可以手动检查第一个参数是否为 undefined。
虽然 combineReducers 自动帮你检查 reducer 是否符合以上规则,但你也应该牢记,并尽量遵守。
示例
- //reducers/todos.js
- export default function todos(state = [], action) {
- switch (action.type) {
- case 'ADD_TODO':
- return state.concat([action.text])
- default:
- return state
- }
- }
- //reducers/counter.js
- export default function counter(state = 0, action) {
- switch (action.type) {
- case 'INCREMENT':
- return state + 1
- case 'DECREMENT':
- return state - 1
- default:
- return state
- }
- }
- //reducers/index.js
- import { combineReducers } from 'redux'
- import todos from './todos'
- import counter from './counter'
- export default combineReducers({
- todos,
- counter
- })
- //App.js
- import { createStore } from 'redux'
- import reducer from './reducers/index'
- let store = createStore(reducer)
- console.log(store.getState())
- // {
- // counter: 0,
- // todos: []
- // }
- store.dispatch({
- type: 'ADD_TODO',
- text: 'Use Redux'
- })
- console.log(store.getState())
- // {
- // counter: 0,
- // todos: [ 'Use Redux' ]
- // }
小贴士
本方法只是起辅助作用!你可以自行实现不同功能的 combineReducers,甚至像实现其它函数一样,明确地写一个根 reducer 函数,用它把子 reducer 手动组装成 state 对象。
在 reducer 层级的任何一级都可以调用 combineReducers。并不是一定要在最外层。实际上,你可以把一些复杂的子 reducer 拆分成单独的孙子级 reducer,甚至更多层。
(二)内部分析
看了第一部分官网的介绍,大家都应该知道了它是如何使用的,但是作为开发人员,我觉得我们有必要思考一下它里面的究竟是如何实现的呢?下面我们来分析一下。
第一步,我们知道reducer 就是一个函数,接收旧的 state 和 action,返回新的 state。知道这点很重要!
第二步,我们来看combineReducers(reducers)方法,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。
那么combineReducers(reducers)返回的就是一个最终的reducer,reducer里面会返回新的state。下面我们结合代码来看:
- const rootReducer = combineReducers({
- reducer1,
- reducer2,
- reducer3,
- ...
- });
这里根reducer暂且起名为rootReducer,它就是通过combineReducers(reducers)返回的。那么combineReducers(reducers)是如何做的呢?
第三步,我们自己来写一个function,来代替combineReducers(reducers)方法,从而来摸索内部是如何实现的,新建一个方法,如下:
- var combineReducers1 = function(obj){
- //内部具体代码
- }
这个方法返回的肯定是一个reducer,那么我们先写出来:
- var combineReducers1 = function(obj){
- //内部具体代码
- //返回最终的reducer
- return reducer;
- }
我们应该能想到下一步该做什么了,既然返回一个reducer,那么我们就要创建一个reducer了,方法接收两个参数,一个是state,一个是action,继续:
- var combineReducers1 = function(obj){
- //内部具体代码
- function reducer(state,action){
- //reducer具体逻辑
- }
- //返回最终的reducer
- return reducer;
- }
reducer最终返回的是一个state,我们接着写:
- var combineReducers1 = function(obj){
- //内部具体代码
- var finalState = {};
- function reducer(state,action){
- //reducer具体逻辑
- //返回state
- return finalState;
- }
- //返回最终的reducer
- return reducer;
- }
那么现在想一想,我们传入的object对象,实际上就是我们传入的所有的reducer方法的集合,实际上里面做的就是分别调用每个reducer方法,将每个reducer方法作为value值赋予我们传入object对象的属性名,通过JavaScript遍历对象获取属性名赋值的方法,我们可以得到最关键的代码,接着往下写:
- var combineReducers1 = function(obj){
- //内部具体代码
- var finalState = {};
- function reducer(state,action){
- //reducer具体逻辑
- for (var p in obj) {
- //根据key属性值调用function(state.属性名,action)
- finalState[p] = obj[p](state[p], action);
- }
- //返回state
- return finalState;
- }
- //返回最终的reducer
- return reducer;
- }
因为我们reducer()方法里传入的state,其实是根state,所以得根据属性名来获取对应的reducer上的state,到这里,关于combineReducers()方法的具体实现我们已经分析完了,了解了combineReducers是如何工作的,那么我们以后的工作才更好的展开,不至于出现了问题而不知道如何解决。
————————————————
版权声明:本文为CSDN博主「胖子爱你520」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/woshizisezise/article/details/51142968
Redux之combineReducers(reducers)详解的更多相关文章
- [Redux] redux之combineReducers
combineReducers combineReducer 是将众多的 reducer 合成通过键值映射的对象,并且返回一个 combination 函数传入到 createStore 中 合并后的 ...
- 详解 Node + Redux + MongoDB 实现 Todolist
前言 为什么要使用 Redux? 组件化的开发思想解放了繁琐低效的 DOM 操作,以 React 来说,一切皆为状态,通过状态可以控制视图的变化,然后随着应用项目的规模的不断扩大和应用功能的不断丰富, ...
- React-Navigation与Redux整合详解
本文转自:文章地址:http://blog.csdn.net/u013718120/article/details/72357698 继react-navigation发布已经过去半年的时间,想必Re ...
- redux详解
redux介绍 学习文档:英文文档,中文文档,Github redux是什么 redux是一个独立专门用于做状态管理的JS库(不是react插件库),它可以用在react, angular, vue等 ...
- Redux 中的CombineReducer的函数详解
combineReducers(reducers) 随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分. combineReducers 辅助函 ...
- dva框架使用详解及Demo教程
dva框架的使用详解及Demo教程 在前段时间,我们也学习讲解过Redux框架的基本使用,但是有很多同学在交流群里给我的反馈信息说,redux框架理解上有难度,看了之后还是一脸懵逼不知道如何下手,很多 ...
- redux-saga框架使用详解及Demo教程
redux-saga框架使用详解及Demo教程 前面我们讲解过redux框架和dva框架的基本使用,因为dva框架中effects模块设计到了redux-saga中的知识点,可能有的同学们会用dva框 ...
- [Hive] - Hive参数含义详解
hive中参数分为三类,第一种system环境变量信息,是系统环境变量信息:第二种是env环境变量信息,是当前用户环境变量信息:第三种是hive参数变量信息,是由hive-site.xml文件定义的以 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
随机推荐
- CA认证和证书
一些概念: PKI:Public Key Infrastructure 签证机构:CA(Certificate Authority) 注册机构:RA(Register Authority) 证书吊销列 ...
- Nginx location模块整理
location模块 Nginx location location 指令的作用是根据用户请求的URI来执行不同的应用,URI就是根据用户请求到的网址URL进行匹配,匹配成功了进行相关的操作. loc ...
- jquery实现input输入框点击加减数值随之变动
<input class="addBtn min" type="button" value="-" /><input cl ...
- Linux下SHA256校验
一.将Hash: SHA256文件和需要检验的文件放在同一个文件夹内 二.$sha256sum -c SHA265 文件 输出: 校验文件:ok
- docker Tomcat镜像
docker中的管理命令 首先需要去下载镜像. [root@CFCA ~]# docker pull tomcat 下载镜像[root@CFCA ~]# docker images ...
- hadoop-httpfs
Hadoop-httpfs: client向httpfs提交文件操作,由httpfs和集群交互: 优势:client不必访问集群 WebHDFS API: https://archive.cloude ...
- Pycharm查看源代码的问题
linear = torch.nn.Linear() # 无法查看Linear的源代码 from torch.nn import Linear linear = Linear() # 可以查看Line ...
- highcharts柱状图、饼状图
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...
- uimgr 子控件主动往管理类注册自己
/// <summary> /// 供UIBehaviour调用,UIBehaviour每个控件都会动态挂载,并且在awake里面调用,注册自己 /// </summary> ...
- 2018-2019-2 20165205 网络对抗技术 Exp7 网络欺诈防范
2018-2019-2 20165205 网络对抗技术 Exp7 网络欺诈防范 实验内容 本次实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法.具体实践有 (1)简单应用SET ...