为什么我们需要状态管理库呢?

学习redux不能只学redux,事实上我们学习的是一种前端状态管理的思维
目前前端状态管理库一般都是基于Flux架构,redux,zustand,pinia,mobx….未来一定还会有无穷多的新轮子出现,我们只有知道为什么需要状态管理,才能更好的学习。
image.png

我们知道react是state直接渲染成dom的,
而redux的做法,是把全局的状态都放在一个集成的store里来管理,这个store是全局唯一的,负责来提供整个应用的state,所有函数的组件都可以放在函数外部的store里,从而由store中的状态的树形关系映射到组件的树形关系上。
image.png

这使得组件的通信更加容易

image.png

在不使用全局管理开发时,要厘清各个组件的状态传递是非常痛苦的,依赖各种传递技巧,你需要不停的思考状态的追踪。父组件的状态需要通过props来通知子组件,而子组件发生变化了之后,需要一个事件暴露出去才能使得父组件感受到他的变化,而兄弟组件通信就更加麻烦了。

有了redux之类的状态管理之后,组件间的通信全都通过store的中转来完成,组件间的相互通信频率就会降低,当store变化,组件能拿到store里的数据,当你的store状态需要变化就useAction去更新store。

redux特性1:唯一数据来源

所有的view的状态来源与store,组件内部尽量不要有自己的state。
store发生更新,view的渲染发生变化;用户交互更改store,触发事件去更新store;

redux特性2:可预测的

state+action=new state
action后会生成一个新的state而不是在原有的state上修改

redux特性3:纯函数更新store

纯函数:没有effect的函数组件,输出结果完全取决于输入参数,完全不依赖外部的参数。
通过action来触发事件,通过reducer的函数去产生store
虽然说是更新store,但是其实本质上是产生了新的store

理解redux的核心:store action reducer

Store

image.png
state是真正的数据,dispatcher是用来dispatch一个函数的方法,reducer来处理这个方法,斌且负责更新store。

#createStore

产生Store只需要调用一个简单的creatStore函数,参数是reducer(一般是合并的reducer)

  1. const Store =createstore(reducer)

store的三个主要方法

1.getState()

得到当前的数据

2.dispatch(action)

用户产生了一个action,store就dispatch出去这个action,给到reducer

3.subscribe(listener)

监听store的变化,当store变化时 ,则调用listener回调
image.png
这里可以订阅store的变化,然后触发后面的log回调。

Action

action就是一个行为对象,里面的type键值对记得要写,方便给reducer辨明你是哪个

  1. //reducer
  2. function reducer(state=initialState,action){
  3. switch(){
  4. case 'PLUS'://要处理action 的type
  5. return Object.assign({},state,{
  6. todos:[...state.todos,{
  7. text:action.text,
  8. completed:false
  9. }]
  10. })
  11. default:return state
  12. }
  13. }
  14. //action Creator如下
  15. //其实就是负责生成一个action 对象
  16. function Plus(x){
  17. return
  18. {
  19. type:'PLUS',
  20. payload:{x}//action函数可以有负载参数
  21. }
  22. }
  23. store.dispatch(Plus(5))

bindActionCreator

就是把createAction和dispatch的操作合成了
image.png
合并成下面一行,bindActionCreators接收Plus这个actionCreator和dispatch实现自动化生成并dispatch action

  1. Plus=bindActionCreators(Plus,store.dispatch)

Reducer

image.png
reducer函数接收两个参数,初始状态initialState(也就是store里的默认初始值,一版来说传入的是待处理的state,如果没有,那需要去自定义一个initialstate)和用户的action。
随后在reducer函数中去判断这个用户触发的事件action该怎么处理,值得注意,一个action通过dispatcher 被dispatch出去后,所有你定义的reducer都会接收到,接收到后通过action.type来判断是否执行,执行也就是生成一个新的store,看上面也就是使用Object.assign(),传入一个空对象,旧state,之后…展开原先store的内容,下面做出更新store的操作。这样之后store上的数据改变了,绑定了store的组件都能订阅更新。
(state,action)=>new state

image.png

combineReducers

combineReducers把一个由多个不同 reducer 函数作为 value 的object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。
合并后的 reducer 可以调用各个子 reducer,并把它们的结果合并成一个 state 对象。state 对象的结构由传入的多个 reducer 的 key 决定。

  1. //reducer一号
  2. export default function todos(state = [], action) {
  3. switch (action.type) {
  4. case 'ADD_TODO':
  5. return state.concat([action.text])
  6. default:
  7. return state
  8. }
  9. }
  10. //reducer二号
  11. export default function counter(state = 0, action) {
  12. switch (action.type) {
  13. case 'INCREMENT':
  14. return state + 1
  15. case 'DECREMENT':
  16. return state - 1
  17. default:
  18. return state
  19. }
  20. }
  1. import { combineReducers } from 'redux'
  2. import todos from './todos'
  3. import counter from './counter'
  4. export default combineReducers({
  5. todos,
  6. counter
  7. })

注:在 reducer 层级的任何一级都可以调用 combineReducers。并不是一定要在最外层。实际上,你可以把一些复杂的子 reducer 拆分成单独的孙子级 reducer,甚至更多层。

组件和store绑定——connect

image.png
组件需要获取store里的数据,组件里的操作也需要更新store,所以我们需要将组件和state绑定,使用connect方法//////////////////////////////////////////////////
WSB05}LCLYST1OEGU9G$QQI.png
image.png

connect()的参数

mapStateToProps(state)

一个基本的性能优化,也就是connect的第一个可选参:return的对象里包裹了这个组件需要使用到的state(state是reducer的返回值,即所有state),而不是全部一起把state传给组件;这里只绑定count,提升性能,把访问的ui结点限制到了最小的范围。否则state里的所有数据变化都会引起ui的变化

image.pngimage.png

mapDispatchToProps(dispatch)

也就是把action绑定到组件上面,在组件上就可以用actions去获取所有redux的action了
image.png

connect的使用image.png

Redux中间件(Middlewares)

当你的组件触发之后执行的action对象里发送了ajax请求、如何处理res的,action到dispatcher之前,先到达中间件,中间件来截获某种类型的action,接收到之后去访问一个Api,根据返回的结果,如果是成功则发一个成功的action。也就是说middleWares接受到这些action之后会进行一个预处理,之后才把真正的action dispatch给reducer,接着更新store。

优雅的管理Action和Reducer

不做管理的一些弊端

—src
——actions
———xxx.js
———xxxx.js
——reducers
———xxx.js
———xxxx.js
1.所有action放在同一个文件,太难管理
2.Action Reducer文件分开,实现业务逻辑时需要来回切换
3.系统中到底有多少action不是很直观

建议的做法/当然更建议的是转toolkit,绷

每一个action写成一个文件,reducer跟在下面
image.png

再开一个Redux文件夹,统一导入Action和Reducer
image.pngimage.png

优势

image.png

后话:Redux官网强烈推荐Redux-Toolkit

即将推出toolkit的文档….