上集精彩
回顾上集:
- 好了,俺要开始学习React了 (基础一) - 掘金 (juejin.cn) ;
- 好了,俺要开始学习React了(基础二) - 掘金 (juejin.cn) ;
- 好啦,俺要开始学React啦(基础三)真是一场酣畅淋漓的写作时刻 - 掘金 (juejin.cn) ;
上集说到了ReactHooks的使用。
本集继续
哎呀哎呀,去大东北和北京玩了半个月,过瘾了😁
该玩也玩了,接下来继续加油吧。
要是俺滴话:Zustand非你不嫁
啥是 Redux
Redux 是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行 。通过集中管理的方式管理应用的状态。Redux是一个稳定、安全、可预测的的状态管理器
圆球相当于一个个组件,左图中组件中的状态分散、组件之间的调取比较麻烦。在大型应用中,往往会用Redux统一管理状态,如右图,不管你状态再多在分散,它都有一个核心的存放处Store,便于统一管理。
配套工具
- 调试工具: 下载谷歌插件:Redux DevTools
- 在React中使用redux,官方要求安装俩个其他插件:
Redux Toolkit(简写RTK 官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式)
react-redux(用来 链接 Redux 和 React组件 的中间件)
上手试试
cmd
npx create-react-app react-redux
npm i @reduxjs/toolkit react-redux
通常在一个应用中,通常集中状态管理的部分都会单独创建一个单独的 store
目录;会有很多个子store模块,所以创建一个 modules
目录,在内部编写业务分类的子store;store中的入口文件 index.js 的作用是组合modules中所有的子模块,并导出store。
实现一个简易加减算数器
- 目录结构
- 在
counterStore.js
采用 @reduxjs/toolkit 创建 counterStore:
createSlice
直译就是创建reducer的切片- 需要一个配置对象作为参数,通过对象的不同属性来指定它的配置
name
用来自动生成action中的typeinitialState
初始化状态statereducers
指定state的各种操作,直接在对象中添加方法- 操作中,会有两个参数:state一个代理对象,可直接修改;action会在下文提到
- 配置根store并组合counterStore模块:
configureStore
用于创建store对象,需要一个配置对象作为参数
- 注入store(react-redux)react-redux负责把Redux和React连接起来,内置Provider组件,通过store参数把创建好的store实例注入到应用中,连接正式建立
这个时候打开调试工具Redux,你就会看到那个reducer了
- 组件中使用store中的数据,需要用到一钩子函数 useSelector,它的作用是把store中的数据映射到组件中: 使用state中的数据
- React组件修改store中的数据需要借助另外一个hook函数 useDispatch,它的作用是生成提交action对象的dispatch函数:
- 提交action传参:在 reducers 的同步修改方法中添加action对象函数,在调用actionCreater的时候传递参数,参数会被传递到action对象payload属性上
redux 异步状态操作
- 使用 @reduxjs/toolkit 创建 channelStore:
- 创建根Store组合子模块:
Redux 中的数据加载问题
RTK Query是一个强大的数据获取和缓存工具。在它的帮助下,Web应用中的加载变得十分简单,它使我们不再需要自己编写获取数据和缓存数据的逻辑。
Web应用中加载数据时需要处理的问题:
- 根据不同的加载状态显示不同UI组件
- 减少对相同数据重复发送请求
- 使用乐观更新,提升用户体验(数据加载失败后保持原有数据显示)
- 在用户与UI交互时,管理缓存的生命周期(相当于实时更新数据并渲染)
这些问题,RTK Query都可以帮助我们处理。首先,可以直接通过RTKQ向服务器发送请求加载数据,并且RTKQ会自动对数据进行缓存,避免重复发送不必要的请求。其次,RTKQ在发送请求时会根据请求不同的状态返回不同的值,我们可以通过这些值来监视请求发送的过程并随时中止。
- 创建Api切片:在
store/modules
下创建channelApi.js
- 在App.js中调用:
你会看到控制台会连续打印好几个对象,虽然对象中的属性都一样,但值会有变化。
- 解构并将数据渲染到页面上:
俺在这就不多说了,想知道更多使用方法:官网:Redux Toolkit | Redux Toolkit (redux-toolkit.js.org)
还有数据持久化:redux-persist - npm (npmjs.com)
啥是 Zustand
这里俺就不介绍了,直接看官网介绍就行了,俺就直接开始撸代码了。
- 创建store:通过
import { create } from "zustand"
异步请求
有个不严谨的地方不知道你有没有发现,如果初始状态多的话,使用 set
修改状态时,会出现错误(俺就说下,不演示了,就是会无法修改对应的状态)可以简单的修改下:
zustand --- 切片模式
当单个store比较大的时候,可以采用切片模式进行模块拆分组合,类似于模块化
不知道为啥,官网给的切片示例俺使不通,然后俺就小改了下,行了:
然后在组件中引入 useStore
并使用。
简化逻辑
- 简化逻辑:Immer 中间件使您能够以更方便的方式使用不可变状态。此外,借助 Immer,您可以简化 Zustand 中不可变数据结构的处理
cmd
npm install immer
- 简化状态获取:
js
const { count, price, increment, decrement, getTotal } = createCounterSlice();
状态获取指定值
- 状态获取指定值:以防止组件重复加载
在 counterSlice.js
中添加个状态 color: "red"
上述代码就会造成组件重复加载,A组件只获取了不变的状态,B组件点击按钮时,B组件重新渲染,而A组件也会重新渲染并打印log,项目一但大了,这样就不行了。
- 解决:需要借助
useShallow
运行后,点击按钮,不会log第二次 ----zustand----
使用Redux DevTools调试
- 使用Redux DevTools调试:借助中间件
devtools
持久化存储
- 持久化存储:借助中间件
persist
- 仅存储指定属性:
partialize
- 指定某些属性不存储:
- 存到哪:
静态方法 setState 和 getState
由于多个组件需要共同去使用或访问同一个状态属性,需要共享,所以把该状态或操作该状态的动作提取出来统一去管理,当当某一个动作只是再一个组件中使用:比如写一个加三的动作,该动作只在B组件中使用(同时官方也推荐这种方法)。
- 将动作提取出来,并单独导出:
上述只是对 zustand 的简单使用,只要在平时的项目中够用就可以了。不会的话再查呗,官网:Zustand (pmnd.rs)
Redux 和 Zustand 更钟意哪个
看完两者的基本使用后,你不难发现,Zustand 相比较于 Redux 会更简单点儿。俺觉得它俩就相当于兄弟。看个人或公司吧,要是公司用的都是 Redux 那就可以不必在意 Zustand ,如果是个人的话,看个人意愿吧。俺会使用 Zustand 会更多点,它上手简单,更适合俺这种新手,同时初期俺也碰不到啥大型的项目。对于中小型的项目来说,Zustand 完全够够的了。但是要是大型项目的话,俺还是建议用 Redux。咋说呢,你可以不精通这两个,但你要都会用这两个(多学点,指定不会亏滴)
下集精彩
好了,停会了,累了😁
下篇俺会讲到哪些知识点呢: 由于刚结束半个月的穷游,精力有点跟不上,原谅解。只要懂得这篇的知识点就很棒了。
- 俺会用一个案例,总结之前说的所有知识点。案例还是用的黑马的美团案例,只不过他用的状态管理是 Redux,俺会用 Zustand 重新写一遍