Redux基础必知必会 reducer拆分 中间件 单向数据流
什么是 redux? 三大原则?
什么是 redux
Redux 是一个基于 js 的全局可预测状态容器,主要用于现代前端框架中进行全局状态管理,能够在不同组件之间进行状态共享
Redux 常与 React 配合使用,但它并非只能用于 React,由于 Vue 官方推出了自己的状态管理库 Vuex,因此 Redux 很少在 Vue 中使用
Redux 的实现借鉴了 Flux, 如单项数据流。但又有别于 Flux,如全局单例 store
redux 三大原则
单一数据源
store 必须是唯一的,全局的 state 存储在单一 store 中state 是只读的
state 只能通过派发 action 来改变reducer 必须是纯函数
reducer 只做一件事情,通过累积的 preState 和当前的 action 计算得出新的 state
相同的输入必须得到相同的结果,因此 reducer 必须是一个纯函数
reducer 中不应该出现副作用,比如发请求
为什么要用 redux
React 的定义是"一个用于构建 UI 界面的 javascript 库",React 关注的点在于如何将状态转换为 UI(UI = fn(state)),在自带的状态管理方案中:
- state: 适用于管理自身状态,也可联合 this.props.chidren 实现 callback render
- props: 适用于父子组件传值,但父子组件嵌套过深时这种方式过于繁琐
- context: 适用于父子组件嵌套过深和兄弟组件共享状态的场景。context 一般是作为局部的状态管理方案而不是全局的,因为 context 一旦更新,Provider 下包裹的所有子组件都会重新渲染,造成性能问题
在一个复杂的应用中,数据的流向存在跨层、反向的数据流, 在交互上也存在父子、兄弟、跨组件通信, 不利于维护
而 Redux 只需要在最外层传入 store, 内层组件即可通过 props 与 store 中的状态交互
在 Redux 中,数据的流动是单向的,store 是全局单一的,reducer 是纯函数,同样的输入得到的输出一定相同,因此状态是可预测的
什么时候用 redux
- 某个组件的状态,需要让其他组件可以随时拿到
- 一个组件需要改变另外一个组件的状态
- 如果你不确定要不要用 redux,那就一定不需要用 redux
redux 基本 api
createStore
createStore 是 redux 的重要组成部分, 大部分 api 都基于它生成
以下是 createStore 的形参列表
- reducer: 初始化、更新 state
- preloadedState: 默认初始化 state,但一般不用它而是 reducer 处理 init action 来初始化一个 state
- enhancer: 一般用于 applyMiddleWare 增加中间件,作用是对 createStore 进行增强,覆盖原来的 dispatch 来实现一些功能上的拓展,如异步 action、日志打印、异常监听
getState
获取 state 的唯一方式,返回当前最新的 state
createStore 内部维持了一个变量 currentState,这个变量是私有的,对外部隐藏,只通过唯一接口 getState 对外暴露
react-redux connect 方法底层也是通过这个 api 拿到 state
dispatch
改变 state 的唯一方式,通过 dispatch 将用户的行为以 action 的形式通知给 redux,通知 redux 把计算最新的状态并反馈给用户
如果你想在 dispatch 的前后做一些拓展功能,比如异步 action,异常收集,日志打印,建议使用中间件来做一些增强
subscribe
订阅 store 的状态变化,当且仅当 dispatch 触发状态更新之后执行入参 callback 回调函数,并返回一个取消订阅时执行的回调函数。
通常我们使用这个 api 来实现 redux 和其他 js 库通信
react-redux 底层在 Provider 中通过 store.subscribe 发起订阅,在 state 改变时,会检查子组件是否通过 connect 消费了 store 以及子组件的 props 有变化,如果这两个条件都满足,就使用最新的状态更新子组件,从而达到精确的最小粒度的 render,相对于 context 一旦数据更新就渲染所有 Provider 包裹的子组件而言,这种处理方式在性能上显然是更优的
redux combineReducers 拆分reducer
随着业务复杂度的增加,把所有状态都放在一个 reducer 中进行处理只会让代码变得更加难以维护
此时可以利用 combineReducers 拆分多个不同的 reducer,对不同业务模块的状态进行分别管理
combineReducers 接受一个 reducers obj 作为入参,你可以给不同 reducer 指定 key,这样调用 getState 时拿到的也是对应 key 的 state
如果多个组件要共享 state,使用相同的 reducer 即可
import {combineReducers, createStore} from 'redux'
import countReducer from './reducer'
import countReducer2 from './count2reducer'
const store = createStore(combineReducers(myCountState:countReducer,myCountState2:countReducer2}))
// store.getState() {myCountState:{...},myCountState2:{...}}
export default store
redux MiddleWare 中间件
如果要记录状态的历史变化,你会怎么做?
我们可能很容易想到只要在 dispatch 前后分别 log 一下就好了
但是一个复杂的大型项目,调用 dispatch 的地方不计其数,上述实现过于臃肿
所以我们应当使用中间件
中间件其实就是对 dispatch 的增强,中间件在 action 到达 store 的前后提供了逻辑插入点,我们可以在上面实现一些异步 action、日志输出、异常检测等功能
使用中间件
通过 applyMiddleWare 传入中间件
const store = createStore(reducer, applyMiddleware(thunk))
redux 数据流向
- 初始化 store,此时 redux 会 dispatch 一个 type 为 init,payload 为 undefined 的 action 并从 reducer 拿到最初的 state
- 组件引入 store 并通过 getState 消费 store 状态,通过 subscribe 订阅 store 状态变化
- 用户动作产生 action,dispatch 派发 action 到 store 并通过 reducer 更新状态。dispatch 的前后如果有中间件会在此时执行中间件相关逻辑
- 状态更新发布之后通知订阅者,订阅者执行注册订阅的回调函数,在回调函数中可以调用 render 将最新的状态展现给用户,并等待用户的下一次动作

Redux基础必知必会 reducer拆分 中间件 单向数据流的更多相关文章
- 迈向高阶:优秀Android程序员必知必会的网络基础
1.前言 网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用 ...
- .NET零基础入门09:SQL必知必会
一:前言 仿佛到了更进一步的时候了,每一个程序员迟早都会遇到数据存储的问题.我们拿什么来存储程序产生的数据?举例来说,用什么来存储我们的打老鼠游戏每次的成绩呢?选择如下: 1:内存中.缺点,退出游戏, ...
- 第5节:Java基础 - 必知必会(下)
第5节:Java基础 - 必知必会(下) 本小节是Java基础篇章的第三小节,主要讲述Java中的Exception与Error,JIT编译器以及值传递与引用传递的知识点. 一.Java中的Excep ...
- 第4节:Java基础 - 必知必会(中)
第4节:Java基础 - 必知必会(中) 本小节是Java基础篇章的第二小节,主要讲述抽象类与接口的区别,注解以及反射等知识点. 一.抽象类和接口有什么区别 抽象类和接口的主要区别可以总结如下: 抽象 ...
- 第3节:Java基础 - 必知必会(上)
第3节:Java基础 - 必知必会(上) 本篇是基础篇的第一小节,我们从最基础的java知识点开始学习.本节涉及的知识点包括面向对象的三大特征:封装,继承和多态,并且对常见且容易混淆的重要概念覆盖和重 ...
- 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入
文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...
- 【MySQL 基础】MySQL必知必会
MySQL必知必会 简介 <MySQL必知必会>的学习笔记和总结. 书籍链接 了解SQL 数据库基础 什么是数据库 数据库(database):保存有组织的数据的容器(通常是一个文 件或一 ...
- Java面试必知必会(扩展)——Java基础
float f=3.4;是否正确? 不正确 3.4是双精度,将双精度赋值给浮点型属于向下转型,会造成精度损失: 因此需要强制类型转换: 方式一:float f=(float)3.4 方式二:float ...
- Java面试必知必会:基础
面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...
随机推荐
- 不带头结点的单链表(基于c语言)
本篇文章的代码大多使用无头结点的单链表: 相关定义: #include <stdio.h> #include <stdlib.h> #include <assert.h& ...
- Docker——questions
服务器的防火墙有什么用?(P14) Tomcat中的webapps.dist这一文件输出目录是用来做什么的?(P15) 容器之间实现数据共享的基础是要在主机有挂载的卷?
- luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP)
luoguP5319 [BJOI2019]奥术神杖(分数规划,AC自动机DP) Luogu 题解时间 难点在于式子转化,设有c个满足的子串,即求最大的 $ ans = \sqrt[c]{\prod_{ ...
- SP接口的全双工首发接口整合
unsigned char bits = 8; unsigned int speed = 50000; unsigned short delay; static void spi_transfer_d ...
- ubuntu16.04启动ssh服务
1 查看ssh服务是否开启 ps -e | grep ssh* 2如果没有则安装ssh apt-get install openssh-server openssh-client 3再看服务就有ssh ...
- java-规约-日期和时间
public class DateTime { public static void main(String[] args) { /**1 * 日期格式化时,传入的pattern表示年份统一用小写的y ...
- Java并发机制(8)--concurrent包下辅助类的使用
Java并发编程:concurrent包下辅助类的使用 整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920397.html 1.CountDown ...
- Java并发机制(6)--阻塞队列
Java并发编程:阻塞队列整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3933404.html 1.什么是阻塞队列 除了同步容器(Hashtable ...
- jQuery--内容过滤和可见性过滤
一.内容过滤 1.内容过滤选择器介绍 :empty 当前元素是否为空(是否有标签体) :contains(text) 标签体是否含有指定的文本 :has(...) ...
- Java程序要操作数据库,一定要使用JDBC技术吗?
<!-- MySQL驱动,连接数据库用,由数据库厂商提供 --> <dependency> <groupId>mysql</groupId> <a ...