简介
React主要的关注点是如何创建可复用的视图层组件,对于组件间的数据传递和状态管理并没有给出很好的解决方案。
基本概念
Redux的主要思想就是描述应用的状态和根据action更新,Redux通过提供一系列的API将这一思想的落地实施进行标准化和规范化。
三大原则
-
唯一数据源
Redux应用只维护一个全局的状态对象,存储在Redux的store中。
唯一数据源是一种集中式管理应用状态的方式,便于监控任意时刻应用的状态和调试应用,减少出错的可能性。
-
保持应用状态只读
在任何时候都不能直接修改应用状态。当需要修改应用状态时,必须发送一个action,由这个action描述如何修改应用状态。
-
应用状态的改变通过纯函数完成
acion表明修改应用状态的意图,真正对应用状态修改的是reducer。
reducer必须是纯函数,所以reducer在收到action时,不能直接修改原来的状态对象,而是要创建一个新的状态对象返回。
纯函数是指满足以下条件的函数:
- 对于同样的参数值,函数的返回结果总是相同的,即,该函数结果不依赖任何在程序执行过程中可能改变的变量;
- 函数的执行不会产生副作用,例如修改外部对象或者输出到I/O设备;
主要组成
Redux应用主要由action、reduce和store三部分组成。
action
action是redux中信息的载体,是store唯一的信息来源。
把action发送给store必须通过store的dispatch方法。
action是普通的JS对象,但每一个action对象都必须有一个type属性描述action的类型,type一般被定义为字符串常量。
除了type属性外,action的结构完全由自己决定。
一般通过action creator创建action,action creator是返回action的函数。
reducer
action用于描述应用发生了什么操作,reducer则根据action做出响应,决定如何修改应用的状态state。
既然是修改state,那么就应该在编写reducer前设计好state。
state既可以包含服务器端获取的数据,也可以包含UI状态。
store
store是redux中的一个对象,也是action和reducer之间的桥梁。
store主要负责以下几个工作:
- 保存应用状态;
- 通过方法getState()访问应用状态;
- 通过方法dispatch(action)发送更新状态的意图;
- 通过方法subscribe(listener)注册监听函数、监听应用状态的改变;
Redux应用中只有一个store,store中保存了唯一数据源。
store通过createStore()函数创建,创建时需要传递reducer作为参数。
Redux数据流过程:
-
调用store.dispatch(action)。一个action是一个用于描述“发生了什么”的对象。store.dispatch(action)可以在应用的任何地方调用,包括组件、XHR的回调,以及定时器;
-
Redux的store调用reducer函数。
store传递两个参数给reducer:
- 当前应用的状态
- action
reducer必须是一个纯函数,它的唯一职责就是计算下一个应用的状态;
-
根reducer会把多个子reducer的返回结果组合成最终的应用状态。根reducer的构建形式完全取决于用户;
redux提供了combineReducers,方便把多个拆分的子reducer组合到一起,但完全可以不使用它;
当使用combineReducers时,action会传递给每一个子reducer处理,子reducer处理后的结果会合并成最终的应用状态;
-
Redux的store保存根reducer返回的完整应用状态;
此时,应用状态才完成更新;
如果UI根据应用状态进行更新,那么这就是更新UI的时机,对于React应用而言,可以在此时调用组件的setState()方法,根据新的应用状态更新UI;
使用Redux
Redux和React并无直接关联,Redux可以和很多库一起使用。
展示组件和容器组件
根据组件的一同不同,可以将组件分为两类:
-
展示组件
展示组件负责应用的UI展示,也就是组件如何渲染,具有很强的内聚性。
展示组件不关心渲染时使用的数据是如何获取的,它只要知道有了这些数据后,组件应该渲染,数据如何获取是容器组件负责的事情。
-
容器组件
容器组件负责应用逻辑的处理,如何发送网络请求、处理返回数据、将处理过的数据传递给展示组件使用等。
容器组件还提供修改源数据的方法,通过展示组件的props传递给展示组件,当展示组件的状态变更引起源数据变化时,展示组件通过调用容器组件提供的方法同步变化。
connect
react-redux提供了一个connect函数,用于把React组件和Redux的store连接起来,生成一个容器组件,负责数据管理和业务逻辑。
示例代码:
const container = connect(mapStateToProps, mapDispatchToProps)(component);
mapStateToProps
mapStateToProps是一个函数,作用是把state转换成props。
state就是Redux store中保存的应用状态,它会作为参数传递给mapStateToProps,props就是被连接的展示组件的props。
每当store中的state更新时,mapStateToProps就会重新执行,重新计算传递给组件的props,从而触发组件的重新渲染。
store中的state更新一定会导致mapStateToProps重新执行,但不一定会触发组件render方法的重新执行。
如果mapStateToProps新返回的对象和之前的对象浅比较相等,组件的shouldComponentUpdate方法就会返回false,组件的render方法也就不会再次被触发。
mapDispatchToProps
容器组件除了可以state中读取数据外,还可以发送action更新state,这就依赖于mapDispatchToProps。
含函数接收store.dispatch方法作为参数,返回展示组件用来修改state的函数。
Provider组件
通过connect函数创建出容器组件,容器组件通过Provider组件获取到Redux的store。
Provider组件需要一个store属性,然后把store属性保存到context。
Provider组件正是通过context把store传递给子组件的,所以使用Provider组件时,一般把它作为根组件,这样内层嵌套的任意组件才可以从context中获取到store对象。
中间件
中间件的概念常用于Web服务器框架,一个请求在经历中间件的处理之后才能到达业务逻辑代码层。
多个中间件可以串联起来使用,前一个中间件的输出时下一个中间件的输入,整个处理过程就如同管道一般。
Redux的中间件概念于此类似,Redux的action可类比Web框架收到的请求,reducer可类比Web框架的业务逻辑层,Redux的中间件代表action在到达reducer之前经过的处理程序。
一个Redux中间件就是一个函数。Redux中间件增强了store的功能。
异步操作
异步操作在Web应用中是不可缺少的,其中最常见的异步操作就是向服务器请求数据。
一般的Redux的工作流:发送action,reducer立即处理收到的action,reducer返回新的state。
此过程并不涉及异步操作,Redux中的异步操作必须借助中间件。
常用的中间件有:
- redux-saga
- redux-promise