什么是 redux? 三大原则?

什么是 redux

Redux 是一个基于 js 的全局可预测状态容器,主要用于现代前端框架中进行全局状态管理,能够在不同组件之间进行状态共享

Redux 常与 React 配合使用,但它并非只能用于 React,由于 Vue 官方推出了自己的状态管理库 Vuex,因此 Redux 很少在 Vue 中使用

Redux 的实现借鉴了 Flux, 如单项数据流。但又有别于 Flux,如全局单例 store

redux 三大原则

  1. 单一数据源

    store 必须是唯一的,全局的 state 存储在单一 store 中

  2. state 是只读的

    state 只能通过派发 action 来改变

  3. 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

  1. 某个组件的状态,需要让其他组件可以随时拿到
  2. 一个组件需要改变另外一个组件的状态
  3. 如果你不确定要不要用 redux,那就一定不需要用 redux

redux 基本 api

createStore

createStore 是 redux 的重要组成部分, 大部分 api 都基于它生成

以下是 createStore 的形参列表

  1. reducer: 初始化、更新 state
  2. preloadedState: 默认初始化 state,但一般不用它而是 reducer 处理 init action 来初始化一个 state
  3. 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 数据流向

  1. 初始化 store,此时 redux 会 dispatch 一个 type 为 init,payload 为 undefined 的 action 并从 reducer 拿到最初的 state
  2. 组件引入 store 并通过 getState 消费 store 状态,通过 subscribe 订阅 store 状态变化
  3. 用户动作产生 action,dispatch 派发 action 到 store 并通过 reducer 更新状态。dispatch 的前后如果有中间件会在此时执行中间件相关逻辑
  4. 状态更新发布之后通知订阅者,订阅者执行注册订阅的回调函数,在回调函数中可以调用 render 将最新的状态展现给用户,并等待用户的下一次动作

Redux基础必知必会 reducer拆分 中间件 单向数据流的更多相关文章

  1. 迈向高阶:优秀Android程序员必知必会的网络基础

    1.前言 网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用 ...

  2. .NET零基础入门09:SQL必知必会

    一:前言 仿佛到了更进一步的时候了,每一个程序员迟早都会遇到数据存储的问题.我们拿什么来存储程序产生的数据?举例来说,用什么来存储我们的打老鼠游戏每次的成绩呢?选择如下: 1:内存中.缺点,退出游戏, ...

  3. 第5节:Java基础 - 必知必会(下)

    第5节:Java基础 - 必知必会(下) 本小节是Java基础篇章的第三小节,主要讲述Java中的Exception与Error,JIT编译器以及值传递与引用传递的知识点. 一.Java中的Excep ...

  4. 第4节:Java基础 - 必知必会(中)

    第4节:Java基础 - 必知必会(中) 本小节是Java基础篇章的第二小节,主要讲述抽象类与接口的区别,注解以及反射等知识点. 一.抽象类和接口有什么区别 抽象类和接口的主要区别可以总结如下: 抽象 ...

  5. 第3节:Java基础 - 必知必会(上)

    第3节:Java基础 - 必知必会(上) 本篇是基础篇的第一小节,我们从最基础的java知识点开始学习.本节涉及的知识点包括面向对象的三大特征:封装,继承和多态,并且对常见且容易混淆的重要概念覆盖和重 ...

  6. 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入

    文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...

  7. 【MySQL 基础】MySQL必知必会

    MySQL必知必会 简介 <MySQL必知必会>的学习笔记和总结. 书籍链接 了解SQL 数据库基础 什么是数据库 数据库(database):保存有组织的数据的容器(通常是一个文 件或一 ...

  8. Java面试必知必会(扩展)——Java基础

    float f=3.4;是否正确? 不正确 3.4是双精度,将双精度赋值给浮点型属于向下转型,会造成精度损失: 因此需要强制类型转换: 方式一:float f=(float)3.4 方式二:float ...

  9. Java面试必知必会:基础

    面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...

随机推荐

  1. SSM集成Thymeleaf

    创建项目 Spring+SpringMVC+MyBatis的配置文件 数据库内容 dao层+service层+controller层 映射文件 前端简单页面 配置tomcat,运行显示 总体项目架构 ...

  2. ZYNQ生成一个工程的基本步骤

    Zynq 7000 SoC 是业界首款All Programmable SoC 组成: PL(FPGA部分) PS(ARM部分) PL和PS数据传输的 高效接口:AXI和ACP PS: 处理系统(Pr ...

  3. CVE-2015-1427(Groovy 沙盒绕过 && 代码执行漏洞)

    1.vulhub环境搭建 https://blog.csdn.net/qq_36374896/article/details/84102101 2.启动docker环境 cd vulhub-maste ...

  4. Dubbo Monitor 实现原理?

    Consumer 端在发起调用之前会先走 filter 链:provider 端在接收到请求时也是 先走 filter 链,然后才进行真正的业务逻辑处理. 默认情况下,在 consumer 和 pro ...

  5. 请解释Spring Bean的生命周期?

    首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy: Spring上下文中的Bean生命周期也类似,如下: (1)实例化Bean: 对于BeanFac ...

  6. rabbitmq 中 vhost 的作用是什么?

    vhost本质上是一个mini版的RabbitMQ服务器,拥有自己的队列.绑定.交换器和权限控制: vhost通过在各个实例间提供逻辑上分离,允许你为不同应用程序安全保密地运行数据: vhost是AM ...

  7. Java Concurrency API 中的 Lock 接口(Lock interface) 是什么?对比同步它有什么优势?

    Lock 接口比同步方法和同步块提供了更具扩展性的锁操作. 他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的 条件对象. 它的优势有: 可以使锁更公平 可以使线程在等待锁的时候响 ...

  8. 什么是 Spring 配置文件?

    Spring 配置文件是 XML 文件.该文件主要包含类信息.它描述了这些类是如何 配置以及相互引入的.但是,XML 配置文件冗长且更加干净.如果没有正确规划 和编写,那么在大项目中管理变得非常困难.

  9. String s = new String(“xyz”);创建了几个字符串对象?

    两个对象,一个是静态区的"xyz",一个是用 new 创建在堆上的对象.

  10. jquery+html5+canvas实现图片 预览 压缩 上传

    javascirpt (function($){ $.fn.extend({ aiiUpload:function(obj) { if(typeof obj !="object") ...