Redux概念简述
- Redux 是全球范围内比较推荐的 和React进行搭配的 数据层框架。
- 无论程序多么复杂,都不需要我们手动传值了,数据传递的过程都是:组件数据改变-> Store改变 -> 其他组件取值
- Redux=Reducer+Flux(Flux是FaceBook公司最早配合React推出的数据层框架,但是它问题很多,所以作者Dan引入Reducer的概念创造了Redux)
复习:React视图层框架
- 在React的文档首页就说明了“A JavaScript library for building user interfaces”,也就是“React是一个用于创建用户接口的JavaScript库”。
- React是轻量型的视图层框架,只能处理简单的数据关系(父子组件中的传值)多几层就只能一层一层传,具体可看笔记围绕 React 衍生出的思考或者下面的例子。
例子
假设 绿色组件 想给很多灰色的组件 传值:
如果我们改变了 绿色子组件 的数据,只使用React就需要先调用 绿色子组件的父组件的方法 改变 父组件中的相关值(第一次子组件向父组件传值),然后使用 同样的方法 层层传递,直到最顶端。
如果我们想要方便的进行传值就需要搭配 数据层框架 结合使用。
使用Redux继续上面的例子
当我们使用Redux时,
- 所有组件的数据都不放在自身,而是放在公共存储区域Store。
- 当绿色组件放在Store中的数据发生改变时,其他灰色组件就会感知到Store中的数据发生变化,自动到Store中获取改变的绿色组件的数据。
- 这样一来绿色组件的数据就很轻松的传给了其他灰色的组件。(实际上不需要有传递这一步)
使用Antd实现TodoList页面布局
- Antd:React的UI框架(React的UI组件库)。
- Antd(Ant Design of React)的**官网**
- antd可以非常方便快捷的完成一个后端的页面布局,但是由于我们接下来做的是用户端,所以可能并不会用到特别多antd。
- 接下来的例子会使用React和Redux重新编写TodoList的页面布局。
安装Antd(React的UI组件库)
在官网中提到,使用 npm 或 yarn 安装:
1 | yarn add antd |
安装完成后重启服务器:
1 | npm start |
使用Antd
引入样式:
1 | import 'antd/dist/antd.css'; // or 'antd/dist/antd.less' |
需要什么组件就引入什么组件,比如我想放入一个<input>框,就可以到官网搜索得到:
选择一个喜欢的,查看他的代码,使用即可:
完整例子:
1 | import React, { Component } from 'react' |

选一个按钮button:
1 | import React, { Component } from 'react' |

加入列表list:
1 | import React, { Component } from 'react' |

Redux的工作流程

注意
获取store中数据时:
- Redux中
store是最重要的,首先就要编写数据存储的仓库(store)。 - 但是光创建
store是没用的,这个“图书管理员”什么都不知道,还需要同时创建“管理员的记录本”**Reducers然后给到这个“图书管理员”store**。 reducer返回(输出)的是一个函数,函数中的 参数state就是整个store中存储的数据(参数action在后面”改变store中数据”中讲)。- 现在
store里已经有数据了,reducer也创建好了,那么组件就可以连接store去里面取数据然后显示出来了。
改变store中数据时:
- 想要改变
store中的数据就需要在 组件 中创建一个action。(在react中,action是一个对象的形式,type属性 描述要做的事情,value属性 为需要传的值。)
【注意:value属性名是自定义的,根据你需要传的值的名字来定】 store提供了一个dispatch方法,**可使用store.dispatch(action)将action传给store**。store将自动将 接收到的数据 和action一起传给reducer,reducer返回的函数中的state就是 上次传过来的数据,action就是组件想要修改state的那句话。reducer会**根据store传来的 上一次的数据(state) 和action整合起来后进行处理,给store返回一个新数据newState**。reducer处理过程:reducer 可以接受state,但是决不能修改state。所以我们需要对store传进来的state进行深拷贝成newState,然后再进行action的处理,最后返回newState给store- 此时页面和
store数据并未同步,需要使用在 组件的构造函数 中使用store.subscribe(this.handleStoreChange);让**组件订阅store**,那么只要store发生改变,handleStoreChange函数 就会被执行一次。 - 在handleStoreChange函数中,使用
getState()获取store中的数据 替换 组件中的state数据,组件的state发生改变后,页面自然重新渲染。
流程总结
获取store数据:
- 创建Redux中的
store(src-store-index.js) - 创建
Reducer(src-store-reducer.js)并将state中 默认数据 设置好 - 在
store中引入Reducer并在创建store时将Reducer作为第一个参数传给store,以便获取 默认state数据(defaultState) - 组件
TodoList.js去连接store,通过store.getState()获取数据然后显示在页面上
改变store数据:
- 点击输入框时,在组件中**创建 对象
action**,type属性 描述要做的事情,value属性 为需要传的值。(TodoList.js-handleInputChange()) - 使用
store.dispatch(action)**将action传给store**。(TodoList.js-handleInputChange()) store自动将 接收到的数据(state) 和action一起传给reducerreducer会根据store传来的 上一次的数据(state) 和action整合起来后进行处理,**给store返回一个新数据newState**(reducer.js中输出的函数中)reducer处理过程:对store传进来的state进行深拷贝成newState,然后再进行action希望的处理,最后返回newState给store- 在 组件的构造函数 中**使用
store.subscribe(this.handleStoreChange);让组件订阅store**,那么只要store发生改变,handleStoreChange函数 就会被执行一次。 - 在handleStoreChange函数中,使用
getState()获取store中的数据 替换 组件中的state数据。那么组件的数据一更新页面自然重新渲染。
使用redux获取store数据(state)
首先需要在项目中添加redux,执行:
1 | yarn add redux |
创建Redux中的store
创建store
在src下创建 文件夹store,在此文件夹下创建index.js用于创建store:
1 | // 引入`redux`库的`createStore`模块 |
创建reducer
在文件夹store下创建**reducers.js用于创建reducer**(state就是整个store中存储的数据)【reducer返回(输出)的是一个函数】:
1 | const defaultState = {}; |
state就是整个store中存储的数据,defaultState是我们定义的默认数据,也就是一开始放在store中存储的数据。
我们知道实际上TodoList需要存储的是两个数据:inputValue和list,所以我们可以将它们放在**默认数据defaultState**中:
1 | const defaultState = { |
stroe中引入reducer
在stroe(index.js)中引入reducer:
在**index.js中引入reducers(图书管理员拿到记录本),并且在创建store时将reducers作为第一个参数传给store**:
1 | import { createStore } from "redux"; |
现在store里已经有数据了,reducer也创建好了,那么组件就可以连接store去里面取数据然后显示出来了。
组件TodoList连接store获取数据
注意:
- 组件引入时,**
./store相当于./store/index.js**,因为会默认到index.js中去寻找组件。 - 组件
store提供了**getState()用于获取store中存储的数据**。
在TodoList.js中删除我们原本列表写死的数据。引入store。使用getState()获取store中存储的数据并保存在组件TodoList的state中。将state中的数据用于input框的value值(输入框默认显示)与list列表的datasource(列表的数据来源):
1 | import React, { Component } from 'react' |

安装chrome插件Redux DevTools
Redux DevTools可以帮助我们进行redux的调试。- “扩展程序” - 打开
Cent Browser网上应用商店 - 搜索Redux DevTools- 添加 :
显示“找不到store,需要跟着指南做配置”。
配置过程
首先需要我们在store文件夹下的index.js中创建store时传入第二个参数:
1 | import { createStore } from "redux"; |
该参数的意思是“如果window下安装了__REDUX_DEVTOOLS_EXTENSION__这个扩展程序就在页面上使用__REDUX_DEVTOOLS_EXTENSION__这个工具”。
此时点开控制面板就可以看到state里面的数据:
使用redux改变store中数据(action)
input框内数据改变时改变store中的值
首先我们希望**input框内数据改变时,state中的inputValue也跟着变。**
在TodoList.js的render函数中,给**input框 绑定onChange事件函数handleInputChange()**:
在TodoList.js的构造函数中,绑定this指向:
【注意:这里的store是顶部import store from "./store";已经引用的store】
1 | constructor(props) { |
在事件函数handleInputChange()中通过打印测试是否能在 input框 中发生改变时获取到 input框 中的 value值:
1 | handleInputChange(e) { |

那么接下来就要告诉store,我想让store中的state的inputValue改成e.target.value。
创建action传给store
那么我们就需要创建一个action,在react中,**action是一个对象的形式,type属性 描述要做的事情,value属性 为需要传的(现在的)值**。store提供了一个dispatch方法,可使用该方法将action传给store:
【注意:这里的store是顶部import store from "./store";已经引用的store】
1 | handleInputChange(e) { |
此时数据已经传递给了store,可是这个“管理员”不知道怎么处理数据,就去查阅“小手册”,所以**store会自动将 接收到的数据 和action一起传给“小手册”reducer。(reducer返回的函数中的state就是 上次传过来的数据,action就是组件想要修改state的那句话)
接下来,reducer会根据store传来的 (上一次的)数据 和action整合起来后,进行处理,给store返回一个新数据newState**。
reducer处理并返回newState
reducer处理过程:reducer 可以接受state,但是决不能修改state。所以我们需要对store传进来的state进行深拷贝成newState,然后再进行action的处理,最后返回newState给store:
1 | // state为store中上一次数据,action由组件发出 |

此时输入“aaa”已经可以在改变store中的state,但页面显示效果还没变。
组件与store数据同步(订阅store)
在组件TodoList.js中,使用store.subscribe()订阅store。只要store发生改变,subscribe()内作为参数的函数就会被执行一次:
【注意:这里的store是顶部import store from "./store";已经引用的store】
1 | constructor(props) { |
当感知到store发生改变时,函数handleStoreChange()就会被执行,函数中将使用getState()获取store中的数据后,使用setatate()来改变 组件 中的state(组件 中的state改变,页面自然重新渲染):
1 | handleStoreChange() { |

此时页面效果就和store中的数据同步了。