action只是描述了“发生了什么事情(导致state需要更新)”,但并不直接参与更新state的操作。state的更新由reducer函数执行。

其基本模式是:(state,action)=> newState

设计组件state的结构:

    在开始敲代码之前,我们要先设计好组件state的结构。我们得先明确state需要哪些变量,哪些是纯粹的数据,哪些和UI有关。用合适的结构组织起来(data类的state和UI类的state最好相互独立)。

In a more complex app, you're going to want different entities to reference each other. We suggest that you keep your state as normalized as possible, without any nesting. Keep every entity in an object stored with an ID as a key, and use IDs to reference it from other entities, or lists. Think of the app's state as a database.

如何处理action:

往reducer函数传入参数之后,根据action的type属性,函数执行对应的对state的更新。文档指出三件在reducer函数中必须避免的事情:

1.改变传入的参数。

2.执行“引发其他作用“的操作,比如调用其他api、路由跳转

3.调用”无更新无关“的函数,如Date.now()

For now, just remember that the reducer must be pure. Given the same arguments, it should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

使用

初始化state:

在第一次调用reducer的时候,传入的state回事一个undefined,此时我们可以给它进行初始化。

 import { VisibilityFilters } from './actions'

 const initialState = {
visibilityFilter: VisibilityFilters.SHOW_ALL,
todos: []
} function todoApp(state, action) {
if (typeof state === 'undefined') {
return initialState
} // For now, don't handle any actions
// and just return the state given to us.
return state
}

我们可以借助ES6的参数默认值简化代码:

 function todoApp(state = initialState, action) {
// For now, don't handle any actions
// and just return the state given to us.
return state
}

最终的reducer可以是这样:

 function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
})
default:
return state
}
}

记住几个地方:

*只要符合switch语句的某个case,返回的state是一个新的对象。

*匹配不到case的,default返回的是原先的state。任何意外的action都不触发state更新,可控才是最重要的。

*Object.assign是ES6的api,许多浏览器可能并不原生支持,开发时记得安装插件 Babel plugin。另,assign第一个参数必须是空对象;也可以用 对象扩展运算符{...state,...update}。

*switch语句不是必须的,reducer内部的结构完全由自己设计

分解(解构)Reducer:

当我们的state涉及很多变量的时候,像上面那样写在同一个函数中难免会显得又长又臭。

作者给出的优化方法是,在Reducer中直接返回一个新的字面量的state。但是这个state各个属性的值是一个reducer(state.key,action)的返回值。

也就是说,返回的state的各个属性,都经过一个reducer的处理,如果该属性的值需要更新。则内部返回一个新属性值。如果该属性不需要更新,则内部返回原来的属性值。

最后store获得的是响应了action的更新了的state。

看下面的例子:

 function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
} function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
} function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}

这段代码结构很清晰,todos函数负责管理事件的添加和‘是否完成’的标记,visibilityFilter负责列表的显示规则,顶层Reducer返回的state的各个属性的值都是一个reducer的返回值。由于内部reducer的函数名和state的属性名一致,所以可以用对象属性简写的方式:return { visibilityFilter,todos};

要留意

内部reducer单元中,参数state都有默认值,因为每个reducer分别更新state的不同属性,因此他们得到的state参数其实是state的一部分属性,他们返回的值也是新state的一部分。

顶层Reducer才是返回新state的地方。

另外,Redux提供了一个工具 combineReducers()来帮助我们实现上面这种分解reducer功能的逻辑:

 import { combineReducers } from 'redux'

 const todoApp = combineReducers({
visibilityFilter,
todos
}) export default todoApp 等价于 export default function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}

就是一个生成Reducer的工具。

Redux:Reducers的更多相关文章

  1. [React Testing] Redux Reducers

    Sometimes we want to test our Redux reducers to make sure they work as expected. In this lesson we w ...

  2. [Redux + Webpack] Hot reloading Redux Reducers with Webpack

    Webpack will hot reload the component, but the reducer we need hard refresh. To sovle the problem, g ...

  3. [Functional Programming ADT] Combine Multiple State ADT Based Redux Reducers

    Redux provides a convenient helper for combining many reducers called combineReducer, but it focuses ...

  4. Redux学习笔记:Redux简易开发步骤

    该文章不介绍Redux基础,也不解释各种乱乱的概念,网上一搜一大堆.只讲使用Redux开发一个功能的步骤,希望可以类我的小白们,拜托它众多概念的毒害,大牛请绕道! 本文实例源代码参考:React-Re ...

  5. react_结合 redux - 高阶函数 - 高阶组件 - 前端、后台项目打包运行

    Redux 独立的集中式状态管理 js 库 - 参见 My Git 不是 react 库,可以与 angular.vue 配合使用,通常和 react 用 yarn add redux import ...

  6. react脚手架改造(react/react-router/redux/eslint/karam/immutable/es6/webpack/Redux DevTools)

    公司突然组织需要重新搭建一个基于node的论坛系统,前端采用react,上网找了一些脚手架,或多或少不能满足自己的需求,最终在基于YeoMan的react脚手架generator-react-webp ...

  7. redux详解

    redux介绍 学习文档:英文文档,中文文档,Github redux是什么 redux是一个独立专门用于做状态管理的JS库(不是react插件库),它可以用在react, angular, vue等 ...

  8. 3.1 开始使用 redux

    前面我们介绍了 flux 架构以及其开源实现 redux,在这一节中,我们将完整的介绍 redux: redux 介绍 redux 是什么 redux 概念 redux 三原则 redux Store ...

  9. Redux(mvc、flux、react-redux)

    其他章节请看: react实战 系列 Redux 关于状态管理,在 Vue 中我们已经使用过 Vuex,在 spug 项目中我们使用了 mobx,接下来我们学习 Redux. 本篇以较为易懂的方式讲解 ...

随机推荐

  1. php的echo 和 return的区别

    来源:https://blog.csdn.net/ljfphp/article/details/76718635 项目中碰到的问题,本来是想在控制器直接return $xml的($xml是一段xml格 ...

  2. Linux下解压rar压缩包

    wget http://www.rarlab.com/rar/rarlinux-x64-4.2.0.tar.gz rar软件不需要安装,直接解压到/usr/local下,以下操作需要有root权限. ...

  3. 《Splunk智能运维实战》——1.7 为本书加载样本数据

    本节书摘来自华章计算机<Splunk智能运维实战>一书中的第1章,第1.7节,作者 [美]乔史·戴昆(Josh Diakun),保罗R.约翰逊(Paul R. Johnson),德莱克·默 ...

  4. MongoDB学习(三)

    MongoDB条件操作符 $gt  > 大于 $lt   < 小于 $gte >= 大于等于 $lte  <= 小于等于 $ne  !=  不等于 条件操作符可用于查询语句中, ...

  5. 用两张图告诉你,为什么你的App会卡顿?

    有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? 知道Android究竟是如何在屏幕上显示我们期望的画面的? 对Android的视图架构有整体把握. 学会 ...

  6. INTERVIEW #0

    一.造成网络延迟的可能原因 1,WiFi所有用户上下行流量共用一个信道,当用户太多或者有人在下载大的资源时带宽不够,丢包: 2,线路质量不佳导致信噪比太低,比如光纤损耗太大等. 二.IPv6优势 1, ...

  7. JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载

    EasyExcel是一个基于Java的简单.省内存的读写Excel的开源项目.在尽可能节约内存的情况下支持读写百M的Excel. github地址:https://github.com/alibaba ...

  8. 疯子的算法总结14--ST算法(区间最值)

    借助倍增和动态规划可以实现O(1)的时间复杂度的查询 预处理: ①区间DP   转移方程  f[i][j] = min(MAX同理)(f[i][j - 1],f[i + ][j - 1])  f[i] ...

  9. python(读取 excel 操作 xlrd 模块)

    一.安装 xlrd 模块 到 python 官网下载 http://pypi.python.org/pypi/xlrd 模块安装,前提是已经安装了 python 环境. 或者在 cmd 窗口  pip ...

  10. java :技巧

    如何查看安装的jdk的路径? 答: 1.情况一:已安装,且环境已配置好 在window环境下,我们先执行java -version 指令查看是否已经配置过java了,如果查到java版本则证明已经安装 ...