在之前的章节 Flux 与 Redux 当中,我们介绍了 Flux 与 Redux 的一些基本概念和它们之间的一些区别,今天我们在来看看另外一个和它们比较类似的 React-Redux,然后在简单汇总一下,比较一下它们三者之间的区别,不过在看 React-Redux 的内容之前,我们先来简单的回顾一下上一章的内容
Flux

传统的 Redux 简化了 Flux 的流程,一般 Flux 的流程是
view触发action中的方法action发送dispatchstore接收新的数据进行合并,触发view中绑定在store上的方法- 通过修改局部
state,改变局部view
Redux
Redux 就是 Flux 思想在 React 当中的实现,它的流程是
view直接触发dispatch- 将
action发送到reducer中后,根节点上会更新props,改变全局view Redux将view和store的绑定从手动编码中提取出来,形成了一个统一的规范最后放在了自己的体系中- 而在基本的
Redux流程中,action只是充当了一个类似于topic之类的角色(类似type属性),reducer会根据这个topic确定需要如何返回新的数据 - 数据的结构处理也从
store中移到了reducer中
Redux 数据流如下图所示

总之记住一句话
Redux的基本原理实际上就是围绕着store进行的
这个 store 不是 Flux 中的 store,而是 Redux 提供的 createStore 方法创建的 store
createStore方法接收reducer函数和初始化的数据(currentState),并将这两个参数并保存在store中createStore时传入的reducer方法会在store的dispatch被调用的时候再被调用,接收store中的state和action,根据业务逻辑修改store中的state
Store
store 中包含 subscribe()、dispatch()、getState() 和 replaceReducer() 这四个方法
- 其中,
subscribe和dispatch顾名思义就是订阅和发布的功能 subscribe接收一个回调(listener),当dispatch触发时,执行reducer函数去修改当前数据(currentState),并执行subscribe传入的回调函数(listener)- 而
getState是获取当前store的state(currentState) - 至于
replaceReducer方法,就是动态替换reducer函数(一般使用较少)
Middleware
下面我们再来简单的了解一下 Redux 中的 middleware,Redux 中的 middleware 简单来说只是针对于 dispatch 方法做了 middleware 处理,也就是说,只接受一个 action 对象,例如官方示例中的
1 | const createStoreWithMiddleware = applyMiddleware( |
Redux 的 middleware 用 reduceRight 的方法,将 applyMiddleware 方法中的参数串起来,原始的 dispatch 方法会最后执行,比如下图所示

而如果需要自定义 middleware 只需要注意这个 middleware 只接收一个 action,执行后也需要返回一个 action,如果需要执行下一步,调用 next(action) 即可
关于中间件的概念,我们会在 中间件 这一章当中详细的来进行介绍
React-Redux
在简单回顾完了 Flux 与 Redux 的一些基本概念之后,下面我们就来看看 React-Redux,其实简单来说 React-Redux 是对 Redux 流程的一种封装,使其可以适配与 React 的代码结构,React-Redux 首先提供了一个 Provider 组件(用来包裹),可以将从 createStore 返回的 store 放入 Context 中,使子集可以获取到 store 并进行操作
1 | <Provider store={store}> |
大致逻辑如下
- 首先
React-Redux提供了connect方法,将原始根节点包装在Connect下,在Connect中的state存储不可变对象,并将state对象中的props和store中的dispatch函数传递给原始根节点 Connect在componentDidMount中,给store添加listener方法(handleChange),每当store中的dispatch被调用时执行handleChange- 而
handleChange会去修改state中的porps,使原始根节点重新render,并且Connect已经在shouldComponentUpdate实现了PureRender功能
handleChange 更新 state 中的 props 逻辑主要由三个函数构成,这三个函数都由 connect 方法传入(前两个参数用的较多)
1 | connect( |
- 第一个函数接收
store中state和props,使页面可以根据当前的store中state和props返回新的stateProps - 第二个函数接收
store中的dispatch和props,使页面可以复写dispatch方法,返回新的dispatchProps - 第三个函数接收前两个函数生成的
stateProps和dispatchProps,在加上原始的props合并成新的props并传给原始根节点的props
React-Redux 中的流程如下图

首先 view 触发 dispatch 然后进入 reducer,修改 store 中的 state ,再将新的 state 和 props 传入 handleChange 中,生成更符合页面的 props,最后传给原始根节点重新 render,下面我们就深入的来了解一下 React-Redux 当中的相关概念,React-Redux 将所有组件分成了以下两大类
UI组件(presentational component)- 容器组件(
container component)
下面我们就分别来看这两类组件
UI 组件
UI 组件有以下几个特征
- 只负责
UI的呈现,不带有任何业务逻辑 - 没有状态(即不使用
this.state这个变量) - 所有数据都由参数(
this.props)提供 - 不使用任何
Redux的API
因为不含有状态,UI 组件又称为纯组件,即它像纯函数一样,纯粹由参数决定它的值
容器组件
容器组件的特征恰恰相反
- 负责管理数据和业务逻辑,不负责
UI的呈现 - 带有内部状态
- 使用
Redux的API
总之,只要记住一句话,
UI组件负责UI的呈现,容器组件负责管理数据和逻辑
在 React-Redux 当中比较常用的 API 就两个,一个是提供的一个组件 <Provider>,另一个就是 connect() 方法
connect()
React-Redux 提供 connect 方法,用于从 UI 组件生成容器组件,connect 的意思就是将这两种组件连起来
1 | import { connect } from 'react-redux' |
上面代码中,connect 方法接受两个参数,mapStateToProps 和 mapDispatchToProps,它们定义了 UI 组件的业务逻辑,前者负责输入逻辑,即将 state 映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 action
connect() 方法有两个比较重要的参数,mapStateToProps 和 mapDispatchToProps(都是函数)
mapStateToProps
官方解释如下
- 如果你传入了这个参数,那么这个组件将会注册
Redux的store的更新信息(简单的可以理解为虚拟DOM那样,即变化了会自动更新) - 即意味着无论什么时候
store更新了,mapStateToProps函数将会被调用 mapStateToProps的返回值必须是一个plain object(简单的对象),这个对象将和组件的props融合,也就是说返回的对象中的key将自动成为组件的props中的成员(就比如上例中的App组件中的参数)- 如果不想订阅
store的更新,可以不用传入该参数,此时使用null来占位即可(不能不传)
抛开官方那些比较繁琐的解释,本质上 mapStateToProps() 就是一个函数,它的作用就是建立一个从(外部的)state 对象到(UI 组件的)props 对象的映射关系,作为函数 mapStateToProps 执行后应该返回一个对象,里面的每一个键值对就是一个映射
1 | const mapStateToProps = (state) => { |
这个函数内部返回的键值对可以被 connect() 传入的参数组件所拿到(上例中的 App),即 App 组件当中可以拿到传递过去的参数(state)(当作 props 来使用),而 </Provider> 中传递的 store 之所以可以被全局使用,也是依靠的这个函数(间接的通过参数传递过去了),然后最重要的一点就是,它可以得到全局唯一的 store 中的 state
mapDispatchToProps
mapDispatchToProps 是 connect 函数的第二个参数,用来建立 UI 组件的参数到 store.dispatch 方法的映射,也就是说,它定义了哪些用户的操作应该当作 action,传给 store,官方解释如下
- 如果传入了第二个参数,并且是一个函数,那么这个函数将获得
dispatch方法(可以发出action,也可以导致state(store) 改变) - 即
connect()方法第一个参数来获得state(但是不能修改),第二个参数可以用来修改state(但是最终都传递回了App组件)
它接收参数 dispatch(dispatch 是 store 中用来分发命令的 API,这里简化了),返回一个总的 actions 清单对象
1 | const mapDispatchToProps = (dispatch) => { |
<Provider>
connect 方法生成容器组件以后,需要让容器组件拿到 state 对象,才能生成 UI 组件的参数,React-Redux 提供 Provider 组件,可以让容器组件拿到 state
1 | import React from 'react' |
在上面的示例当中,Provider 在根组件外面包了一层,这样一来 App 的所有子组件就默认都可以拿到 state 了