react进阶-redux
开始
Redux,一种新型的前端“架构模式”。经常和 React.js 一并提出,你要用 React.js 基本都要伴随着 Redux 和 React.js 结合的库 React-redux。
要注意的是,
Redux和React-redux并不是同一个东西。Redux是一种架构模式(Flux 架构的一种变种),它不关注你到底用什么库,你可以把它应用到React和Vue,甚至跟jQuery结合都没有问题。而React-redux就是把Redux这种架构模式和React.js结合起来的一个库,就是Redux架构在React.js中的体现。
安装redux和 react-redux
1 | npm i -S redux react-redux |
那么如何去使用它们? 首先得了解provider组件,和connect以及store,action,reducer.
解析 redux
redux中含有store,action,reducer.redux的作用是什么? 它们是如何工作的.
redux的作用就是用来管理数据状态的.
随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。
管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。
store,action,reducer是如何协调工作的?
假设我们有一个事情清单要维护:
1 | const state = { |
我们如何去维护这些数据? 比如增加一个要做的事情.
而reducer就是做这个工作的,它完成了数据的初始化,并且决定了对这个数据有哪些行为.并且它还是一个纯函数(即不对参数进行修改的函数),要保证只要输入的参数一样,那么结果一定相同.
1 | const defaultState = { |
我们只能够通过这个todoReducer来操作数据,以上我们需要传入行为action,定义操作的类型以及数据.显然这样通过字符串的形式来判断行为,是不行的.所以我们可以预先定义action,然后再传入,可以联想到设计模式中的工厂模式.
action.js:
1 | export const actionType = { |
acitonType规定了aciton的有那些行为,并且提供了一些action,这里我们演示只有一个增加的action.
然后我们reducer就能够写成:
1 | import { actionType } from './action'; |
这样子的话,我们可以通过获取action,给reducer来完成我们对数据的操作.
那么我们如何获取state数据? 如果有一个getter函数就好了,这就是store,并且它还封装了reducer.
store.js
1 | import todoReducer from './todoReducer'; |
这里的store有获取state的方法getState,还有对其操作的函数dispatch.故我们只要通过store就能够对数据进行操作.
示例:
1 | import store from './store'; |
这里我们增加了两个事件,验证一下:

这就是redux的工作原理,还有一个问题就是store就像是全局变量,可能两个组件的数据变量可能会重复,会出现不方便维护,解决方案是我们为每个组件设置成单独的数据域,就好像:
1 | { |
类似这种效果,这样也不会产生数据的污染.
redux恰好就提供了combineReducers函数来实现这个效果.它就是结合reducer来为索引.
先创建一个总的 reducer:
1 | import { combineReducers } from 'redux'; |
这里将刚才的todoReducer放进去总reducer.
然后我们的store引入该reducer:
1 | import rootReducer from './rootReducer'; |
createStore,是redux已经帮我们写好了,我们直接用就行.
1 | constructor(props) { |
我们同样的对其进行打印,看看数据是否有变化.

我们可以看到,store保存的数据结构已经发生了变化,已经开始分区域保存数据,实际保存数据的其实是reducer,只不过store包含了所有的reducer.
结合 react-redux
React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据.
react-redux提供了两个东西,<Provider/>组件和connect函数.
React-Redux将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。UI 组件:
只负责 UI 的呈现,不带有任何业务逻辑,没有状态(即不使用this.state这个变量,所有数据都由参数(this.props)提供,
不使用任何 Redux 的 API.
容器组件:
容器组件的特征恰恰相反,负责管理数据和业务逻辑,不负责 UI 的呈现,带有内部状态,使用 Redux 的 API
Provider
React-Redux 提供<Provider/>组件,能够使你的整个app访问到Redux store中的数据.
源码:
1 | class Provider extends Component { |
可以看到其作用就是将store绑定在了上下文对象context,然后子组件就可以通过context获取到store.
connect()
connect方法,用于从 UI 组件生成容器组件.
1 | import React, { Component } from 'react' |
它从context获取了store,并且将store里的数据,通过props注入到了组件,所以组件可以通过props里读取store里的数据,而mapStateToProps,顾名思义就是将store里的state映射到组件的props.
还能继续深入对dispatch进行映射,同样映射到props里,并且数据dispatch之后要重新渲染组件.
1 | export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => { |
这样就也就完成了state和dispatch映射到props的过程.
实际上react-redux已经封装了该函数,所以我们直接用就行了.
示例: 将 redux和react结合起来,图像化.
1 | import React from 'react'; |
这里我们返回的是一个由connect生成的容器组件.并且完成了映射,将state.todoReducer.todos映射到了props.todos上,dispatch也是如此.所以在组件里,我们直接用props调用就行了,TodoList就是简单的react组件.
附上TodoList.js:
1 | import React, { Component } from 'react'; |
以及Todo.js:
1 | import React, { Component } from 'react'; |
记住一定要
connect生成的组件一定要在<Provider/>下才能有效,因为connect要通过context获取store,而store放在context的过程是有<Provider/>,前面已经讲过了.
1 | import { Provider } from 'react-redux'; |
最后的效果:

- 本文作者: Veng
- 本文链接: http://veng0923.github.io/2020/03/18/react进阶-redux/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!