React | 再战Redux

简介: React | 再战Redux

一、认识ReduxToolkit

认识Redux Toolkit

  • Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法
  • 在前面我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦
  • 并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理)
  • Redux Toolkit包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题
  • 在很多地方为了称呼方便,也称为"RTK"


  • 安装Redux Toolkit:
  • Npm install @reduxjs/toolkit react-redux


  • Redux Toolkit的核心API主要有以下几个:
  • configureStore:包装createStore以提供简化的配置选项和良好的默认值.它可以自动组合你的slice reducer,添加你提供的任何Redux中间件,redux-thunk默认包含,并启用Redux DevTools Extension
  • createSlice:接收reducer函数的对象,切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions
  • createAsyncThunk:接收一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk

二、ReduxToolkit重构

重构代码 – 创建counter的reducer

  • 我们先对counter的reducer进行重构:通过createSlice创建一个slice
  • createSlice主要包含如下几个参数:
  • name:用户标记slice的名词
  • 在之后的redux-devtool中会显示对应的名词


  • initialState:初始化值
  • 第一次初始化时的值


  • reducers:相当于之前的reducer函数
  • 对象类型,并且可以添加很多的函数
  • 函数类似于redux原来reducer中的一个case语句
  • 函数的参数:
  • 参数一:state
  • 参数二:调用这个action时,传递的action参数


  • createSlice返回值是一个对象,包含所有的actions

6eb43d9bbc1e43e9a80c350970872750.png

重构代码 – 创建home的reducer

53eb576015a942cfa65367d69852ff00.png

store的创建

  • configureStore用于创建store对象,常见参数如下:
  • reduce:将slice中的reducer可以组成一个对象传入此处
  • middleware:可以使用参数,传入其他的中间件(自行了解)
  • devTools:是否配置devTools工具,默认为true

1d6bc9c80c754da89fc7c20b61b4b7d5.png

三、ReduxToolkit异步

Redux Toolkit的异步操作

  • 在之前的开发中,我们通过redux-thunk中间件让dispatch中可以进行异步操作
  • Redux Toolkit默认已经给我们集成了Thunk相关的功能:createAsyncThunk
  • 当createAsyncThunk创建出来的action被dispatch时,会存在三种状态:
  • pending:action被发出,但是还没有最终的结果
  • fulfilled:获取到最终的结果(有返回值的结果)
  • rejected:执行过程中有错误或者抛出了异常


  • 我们可以在createSlice的entraReducer中监听这些结果:

5c932094f13642e0a7de371b5022db5d.png

extraReducer的另外一种写法

  • extraReducer还可以传入一个函数,函数接收一个builder参数
  • 我们可以向builder中添加case来监听异步操作的结果:

02d3fc326e824eac9fd9fd5321f3e276.png

Redux Toolkit的数据不可变性

  • 在React开发中,我们总是会强调数据的不可变性:
  • 无论是类组件中的state,还是redux中管理的state
  • 事实上在整个JavaScript编码过程中,数据的不可变性都是非常重要的


  • 所以在前面我们经常会进行浅拷贝来完成某些操作,但是浅拷贝事实上也是存在问题的:
  • 比如过大的对象,进行浅拷贝也会造成性能的浪费
  • 比如浅拷贝后的对象,在深层改变时,依然会对之前的对象产生影响


  • 事实上Redux Toolkit底层使用了immerjs的一个库来保证数据的不可变性


  • 为了节约内存,又出现了一个新的算法:Persistent Data Structure(持久化数据结构或一致性数据结构)


  • 用一种数据结构来保存数据


  • 当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费

四、connect高阶组件

自定义connect函数,context处理store

deb45736507c49d1a42ec41604143ac9.png

b0786eb2aab94bf6a4b44071efcf1a27.png

ee2a255b36064f4095443cb60a08c240.png

五、中间件的实现原理

打印日志的需求

  • 中间件的目的是在redux中插入一些自己的操作:
  • 比如我们现在有一个需求,在dispatch之前,打印一下本次的action对象,dispatch完成之后可以打印一下最新的store state
  • 也就是我们需要将对应的代码插入到redux的某部分,让之后所有的dispatch都可以包含这样的操作


  • 如果没有中间件,我们是否可以实现类似的代码呢?可以在派发的前后进行相关的打印


  • 但是这种方式缺陷非常明显:
  • 首先,每一次的dispatch操作,我们都需要在前面加上这样的逻辑代码
  • 其次,存在大量重复的代码,会非常麻烦和臃肿


  • 是否有一种更优雅的方式来处理这样的相同逻辑呢?
  • 我们可以将代码封装到一个独立的函数中


  • 但是这样的代码有一个非常大的缺陷:
  • 调用者(使用者)在使用我的dispatch时,必须使用我另外封装的一个函数dispatchAndLog;
  • 显然,对于调用者来说,很难记住这样的API,更加习惯的方式是直接调用dispatch;

修改dispatch

  • 事实上,我们可以利用一个hack一点的技术:Monkey Patching,利用它可以修改原有的程序逻辑
  • 我们对代码进行如下的修改:
  • 这样就意味着我们已经直接修改了dispatch的调用过程
  • 在调用dispatch的过程中,真正调用的函数其实是dispatchAndLog


  • 我们可以将它封装到一个模块中,只要调用这个模块中的函数,就可以对store进行这样的处理:

5cc745f2b7cf431881fc86180b761197.png

thunk需求

  • redux-thunk的作用:
  • 我们知道redux中利用一个中间件redux-thunk可以让我们的dispatch不再只是处理对象,并且可以处理函数;
  • 那么redux-thunk中的基本实现过程是怎么样的呢?事实上非常的简单。


  • 我们来看下面的代码:
  • 我们又对dispatch进行转换,这个dispatch会判断传入的

4bfc58018ce147d3b2a46a1bdb5f388a.png

合并中间件

  • 单个调用某个函数来合并中间件并不是特别的方便,我们可以封装一个函数来实现所有的中间件合并:

fd54d32951ac4d279e650dd8b800bd9b.png

231a6828e5f4473c8366b3f11cbe34e3.png

  • 我们来理解一下上面操作之后,代码的流程

25fc3add288d4196adad72d09653fe97.png

  • 当然,真实的中间件实现起来会更加的灵活,这里我们仅仅做一个抛砖引玉,有兴趣可以参考redux合并中间件的源码流程

六、React状态管理选择

React中的state如何管理

  • 我们学习了Redux用来管理我们的应用状态,并且非常好用(当然,你学会前提下,没有学会,好好回顾一下)
  • 目前我们已经主要学习了三种状态管理方式:
  • 方式一:组件中自己的state管理
  • 方式二:Context数据的共享状态
  • 方式三:Redux管理应用状态


在开发中如何选择呢?

  • 首先,这个没有一个标准的答案
  • 某些用户,选择将所有的状态放到redux中进行管理,因为这样方便追踪和共享
  • 有些用户,选择将某些组件自己的状态放到组件内部进行管理
  • 有些用户,将类似于主题、用户信息等数据放到Context中进行共享和管理
  • 做一个开发者,到底选择怎样的状态管 理方式,是你的工作之一,可以一个最好的平衡方式(Find a balance that works for you, and go with it.)
相关文章
|
23天前
|
存储 JavaScript 前端开发
掌握现代Web开发的基石:深入理解React与Redux
【10月更文挑战第14天】掌握现代Web开发的基石:深入理解React与Redux
28 0
|
22天前
|
存储 JavaScript 前端开发
React中使用redux
【10月更文挑战第15天】
29 3
|
1月前
|
存储 JavaScript 前端开发
如何使用React和Redux构建现代化Web应用程序
【10月更文挑战第4天】如何使用React和Redux构建现代化Web应用程序
|
1月前
|
JavaScript 前端开发
使用 React 和 Redux 构建动态图表应用
【10月更文挑战第3天】使用 React 和 Redux 构建动态图表应用
|
1月前
|
JavaScript 前端开发
使用 React 和 Redux 构建一个计数器应用
【10月更文挑战第3天】使用 React 和 Redux 构建一个计数器应用
|
1月前
|
存储 JavaScript 前端开发
|
1月前
|
前端开发 JavaScript 网络架构
实现动态路由与状态管理的SPA——使用React Router与Redux
【10月更文挑战第1天】实现动态路由与状态管理的SPA——使用React Router与Redux
28 1
|
3月前
|
存储 JavaScript 前端开发
React中使用redux
React中使用redux
134 56
|
30天前
|
前端开发 JavaScript
深入理解前端状态管理:React、Redux 和 MobX
【10月更文挑战第7天】深入理解前端状态管理:React、Redux 和 MobX
25 0
|
3月前
|
存储 JavaScript 前端开发
react redux 实现原理
【8月更文挑战第29天】react redux 实现原理
25 4