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% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...
随机推荐
- Gin 09 HTTP 重定向
gin http 重定向有两种方法,重写url 和 不重写的跳转.两种方法,gin 通过两个内置方法实现: demo package main import ( "github.com/gi ...
- Java基础——StringBuilder的添加与反转方法
StringBuilder添加与反转方法 方法 返回对象 public StringBuilder append(任意类型) 添加任意参数数据,并返回对象本身,注意:返回的是对象本身,则调用过appe ...
- vue学习过程总结(05) - vue的重要插件vue-router
vue-router的中文文档:https://router.vuejs.org/zh/installation.html(基于文档的摘抄) 1.vue中的组件与插件 转载:https://blog. ...
- Discuz!X系列全版本后台sql注入复现
圈子某位大佬公布的0day,拿来刷一刷,漏洞分析请移步大佬文章.大佬链接 0x01 环境准备 1.首先去码云下载最新版本的discuz(DiscuzX 3.4 R20191201). 2.将upaod ...
- Cobalt Strike之网站克隆
点击 attack --> Web-dirve-by --> clone file 填写你要克隆的网站.带有端口 Clone URL:克隆目标网站的URL 注意问题:URL需要添加http ...
- 解决centos7服务器shadows已启动但是无法连接的问题
firewall-cmd --permanent --add-port=8989/tcp firewall-cmd --reload 这是由于centos7防火墙并没有开放ss端口的问题 添加json ...
- MATLAB批量打印输出600PPI的图像且图像不留空白
一 前言 最近收到审稿人的修改意见,其中有三条:一条为<RC: There were only five images evaluated in the experiment, and I re ...
- Java中的软引用、弱引用、虚引用的适用场景以及释放机制
Java的强引用,软引用,弱引用,虚引用及其使用场景 从 JDK1.2 版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引 ...
- MyBatis 与 Hibernate 有哪些不同?
1.Mybatis 和 hibernate 不同,它不完全是一个 ORM 框架,因为 MyBatis 需要 程序员自己编写 Sql 语句. 2.Mybatis 直接编写原生态 sql,可以严格控制 s ...
- jQuery对象的创建
1.js类库 JavaScript封装了很多的预定义的对象和实用函数,能帮助使用者建立有高难度交互 客户端页面,并且兼容各大浏览器.跑在浏览器,请求服务器 当前比较流行的js库: jquery EXT ...