概述
Redux是一款用于管理前端状态的库,但是集成一些附属库有助于大大提高Redux的开发效率。本文所有的库都是在React背景下使用;本文是开发笔记,非教程,适合有一定经验的开发者阅读。
为什么要用Redux
官方文档讲了很多,传统的前端开发有很多缺点:
- 随着现代前端应用变得越来越庞大,需要管理的状态越来越多;
- 模型更新视图,视图更新模型,前端状态失控;
- 需求经常变动,且难以维护变化和异步性(mutation and asynchronicity)。
一句话:使用Redux是为了更好地管理状态。
Redux三大原则
- 单一数据源,一个前端应用只有一颗状态树;
- 状态只读,状态不应该被手动改变;
- 状态只能通过纯函数改变,纯函数只接收两个参数,前一刻的状态,以及一个动作;只有一个功能,计算下一刻的状态(必须返回一个深复制的状态对象)。
Redux生态系统
Redux生态系统越来越繁荣,为了方便Redux的开发,有很多实用性很强的库涌现了出来。
Redux中的标准动作
Flux Standard Action
Redux的思想源于Flux,Flux对于一个标准的动作是有定义的,一个FSA(Flux Standard Action)必须符合下面的条件。
一个FSA必须:
- 是一个JSON对象;
- 有type属性。
一个FSA可能:
- 有payload属性;
- 有error属性;
- 有meta属性。
一个FSA必须不能
- 含有除type,payload,error,meta以外的任何属性。
注意FSA中,type用于描述类型,payload用于装载数据,error用于判别当前动作是否用于描述错误(如果是true则表示是,否则其他任何值都表示否),meta用于描述其他信息(很少用到)。
Redux-Actions
Redux-Actions就是一个用于为Redux提供FSA,并且负责提供构建处理FSA的reducer的三方库。
使用Redux-Actions创建一个动作。
1 | // data action types |
创建一个Reducer。
1 | // user list state reducer |
上面代码片段中,handleActions()函数接收两个参数,第一个是一个对象,键是动作,值是对应的纯函数;第二个值是初始状态。
Immutable对象
注意上面的代码中的fromJS()和List([])。这两个函数是Immutable中的API。
Immutable是Facebook推出的一款解决常量和对象深复制问题的不可变集合对象的库,它的特点是所有Immutable对象都是不可变的,对Immutable对象进行的任何操作都不会在原有对象上进行改变,而是返回一个内存全新的对象。
例如我们需要创建一个Redux的初始状态,我们可以使用Immutable的Map()来创建。
1 | import { Map } from 'immutable'; |
或者当需要将一个复杂得JSON对象转换为Immutable对象时,可以使用Immutable的fromJS()方法来创建。
1 | import { fromJS } from 'immutable'; |
当我们需要将Immutable对象转换为JSON对象时可以使用toJS()。
1 | const obj = immutableObj.toJS(); |
修改对象使用set(k, v)方法,获取值使用get(k),更多API,请查阅官网。
Redux-Observable
Redux-Observable负责解决Redux中的异步动作问题,该库基于RxJS。推荐一个YouTube上的视频:React + Redux + RxJS = Amazing!,主讲者就是Redux-Observable的作者。
RxJS
在使用Redux-Observable之前,需要对RxJS有一个基本的了解。RxJS是一个基于Observable的响应式编程库,用于使编写基于回掉函数的代码变得更容易。官网对于RxJS的一句话解释是:可以把RxJS当成处理事件的Lodash。
来看官网的示例。
1 | var button = document.querySelector('button'); |
将按钮单击事件转换为一个Observable,并注册一个响应函数。
Redux-Observable处理AJAX
对于一次异步动作的处理流程,Redux-Observable引入了一个Epic(笔者习惯译为“迁徙”,待讨论)的概念。
一次迁徙就是一个动作的流程。
1 | import 'rxjs/Rx'; |
上述代码定义了一个Epic,当触发了APP_FETCHING_USER事件时,发送AJAX请求,如果响应成功,则依次执行一系列后续动作,否则执行获取用户列表失败动作。
然后需要将所有的Epic作为中间件交给Redux管理。
1 | // ... |
Redux-Form
基本使用
在实际过程中,一个应用会有很多状态需要处理,尤其是对于表单的状态,每次维护这些状态都需要写重复的代码。Redux-Form就是配合Redux解决表单状态管理的一个库。
1 | // AddForm.jsx |
上述代码中的Field组件的component属性,实际上是我们自己写的自定义组件,该组件中有且仅有一个表单元素。
1 | <!-- ... --> |
而validate属性中传入的数组所包含的对象都是函数类型,这些函数都接收一个参数作为待验证的值。
Validator
Validator是一款功能齐全的用于验证的库,配合Redux-Form实现表单验证功能。
1 | export const required = value => value ? undefined : 'Required'; |
这些就是AddForm.jsx中validate被赋值的数组中的元素。
React-Router 和 React-Router-Redux
使用React框架的单页应用很多都在使用React-Router做前端路由,而配合React-Router-Redux可以实现对浏览器历史路径的状态管理。
1 | // ... |
仅上面这样处理一下,单页应用的history状态也会被Redux管理起来。