2020.12.13 星期日 21:35
实际状态管理项目
实际使用了redux,也是得益于其“啰嗦”的设计,把所有reducer 定义于一处,包括定义action。清晰,方便查找/追踪state
没有使用immutable。但是确实做了一些性能优化的处理,包括state及某个属性如何更新等。
redux 简单强大,刚好满足。不需要再去学习新框架dva
mobx 使用简单,灵活,同样的和redux,dva 需要学习新的状态管理概念/文档。用generator语法糖,增加配置成本。
每一个需要监听的state/属性/action,需要用@observable,@action 去处理。也可以不去监听,混合在一起。
虽然装饰器使得语法明了。但是redux 数据流,有明确的规定,必须先定义action(type,payload),然后去操作reducer。
若在业务项目中使用,无聊mobx或dva 都是非常不错了。奈何更需要的是一个状态(集中)管理的简单库。
如果偏业务,redux确实有一些啰嗦。
github 对比
统计于 20201214
– | star | issues | fork | note |
---|---|---|---|---|
redux | 54.9k | 33/1802 | 14.5k | |
mobx | 22.9k | 12/1633 | 1.9k | |
dva | 15.3k | 22/2072 | 3k | |
– | – | – | – | |
recoil | 17.2k | 161/689 | 929 | 统计于20220722 |
redux
github: https://github.com/reduxjs/redux
redux文档
dva
github: https://github.com/dvajs/dva/blob/master/README_zh-CN.md
dva 文档
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
MobX
github: https://github.com/mobxjs/mobx
MobX 以前叫做 Mobservable
SMTC
1 | // 我们定义一个可观测的store |
mobx-react
原理
REDUX的好处
通过action,reducer来完成应用的数据流管理,逻辑简单清晰
reducer函数式的设计,让我们代码变得可观测,可回溯
action的设计,特别适用于多数据联动的场景
REDUX的弊端
啰嗦代码太多
reducer无复用性
性能优化太繁琐(当然可以引入immutable来解决,但是是不是又增加了学习成本,应用的复杂度和代码量呢)
app state和store state的划分
在实际开发中,一方面我们受益于redux的好处,但另一方面我们也受制于redux的弊端,其实某种程度制约了我们的开发效率,因此近端时间学习了下mobx,从它这里找到了能提升开发效率的方法,不是说mobx比redux好,而是mobx更适合我们实际的工作内容,而redux更实用与大型项目的开发
MobX
从这张图我们可以看到mobx其实就是mvvm的概念,数据双向绑定,并且能做到字段级的控制,所以用mobx开发react的项目,我们不需要做太多的性能优化,同时它的store是可以复用的,这对我们快速开发项目特别有帮助
至此,mobx-react的工作原理基本梳理清楚了,大致用一下几句话来概括
1.observe组件第一次渲染的时候,会创建Reaction,组件的render处于当前这个Reaction的上下文中,并通过track建立render中用到的observable建立关系
2.当observable属性修改的时候,会触发onInvalidate方法,实际上就是组件的forceupdate,然后触发组件渲染,又回到了第一步
这篇就先到这里告一段落,后面会对action,compute,atom做进一步的分享
compute
运行到代码1处,通过第一节的分析,autorun的Reaction跟fullName建立观测的关系,而通过上面的分析,compute的帅帅的
+this.name表达式跟computeValue的Reaction建立了观测关系
当我们运行p.changeName的时候,根据前面的知识,会触发observer的onBecomeStale,不过computeValue的onBecomeStale跟Reaction的onBecomeStale不一样
action
从源码可以看出,核心就是通过startBatch和endBatch完成一个批量的操作,也就是说我们在executeAction无论改变多少次observable的值,最终只会触发一次Reaction的onInvalidate
对比
dva
经朋友推荐开始接触 dva ,从 2.x 版本开始使用,我也基于这个工具开发了一套项目模版,它简化了 redux 的使用,并且在封装了 redux-saga 和 react-router,同时还可以包含 dva-loading 插件获取 loading 状态等。
在 redux 时代,当我需要新增一种跨页面全局数据的时候,我需要去项目的 reducers 目录定义一下这种数据命名和初始值,然后在 constans 目录中为更改这项数据的操作定义一种唯一的操作类型(type),再去 actions 目录定义一些方法,这些方法最后会得到更改后的数据和操作类型(type),最后再回到 reducers 中根据这个操作类型(type)把数据整合到 reducer 中…可以看到,我在编写 redux 这部分代码的时候需要频繁在 actions 、 constants 、 reducers 这几个目录间切换。
而使用 dva 就可以免除这些困扰了,我只需要一个 model 中就可以完成所有操作:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// app全局性状态管理
import * as appApis from '../services/app'; // 异步请求接口
export default {
namespace: 'app',
state: {
channels: [],
show: true
},
reducers: {
getChannelsAndGamesSuccess(state, { channels, games }) {
return { ...state, channels, games };
},
changeShow(state, { show }) {
return { ...state, show };
}
},
effects: { // 异步
* getChannelsAndGames(_, { call, put }) {
const res = yield call(appApis.getChannelsAndGames);
yield put({
type: 'getChannelsAndGamesSuccess',
channels: res.channels
});
}
},
subscriptions: { // 订阅
setup({dispatch, history}) {
history.listen(location => {
if (location.pathname == '/') {
dispatch({
type: 'getChannelsAndGames'
});
}
});
}
}
};
mobx
既然 dva 这么好用,为什么还要使用 mobx 呢?还不是为了折腾😅,用了才能知道两者的优劣,同样的基于 mobx 我也创建了一个项目模版。
在使用 dva 的时候,但凡遇到异步请求的时候都需要先定义一个 effects ,请求完成后再触发一个 action 去修改数据,于是,强迫症作怪,这两者的命名总是让我感觉难受和啰嗦,你可以看到我都是定义为 getXxx 和 getXxxSuccess。
action 是修改 state 的唯一途径,是的,所有的状态管理库都是这样的,但是 mobx 通过一些工具函数解决了这一问题:
以上是我最喜欢的两种写法,分别借助了 runInAction 和 asyncAction 这两个工具函数,当然,还有其他方法可以参考。
recoil
recoil-动机: https://recoiljs.org/zh-hans/docs/introduction/motivation
动机
出于兼容性和简便性的考虑,相比使用外部的全局状态,使用 React 内置的状态管理能力是个最佳的选择。但是 React 有这样一些局限性:
组件间的状态共享只能通过将 state 提升至它们的公共祖先来实现,但这样做可能导致重新渲染一颗巨大的组件树。
Context 只能存储单一值,无法存储多个各自拥有消费者的值的集合。
以上两种方式都很难将组件树的顶层(state 必须存在的地方)与叶子组件 (使用 state 的地方) 进行代码分割。
我们希望改善上述的问题的同时,不仅能保留 API 以及语义,还能使其的表现尽可能保持 React 的样子。
Recoil 定义了一个有向图 (directed graph),正交同时又天然连结于你的 React 树上。状态的变化从该图的顶点(我们称之为 atom)开始,流经纯函数 (我们称之为 selector) 再传入组件。基于这样的实现:
React组件设计实践总结05 - 状态管理
## 状态管理
## 你不需要状态管理
## 你不需要复杂的状态管理
## Redux
七,可能还有性能问题
Redux 常见问题:性能
redux 中的 state 树太大会不会有性能问题?
我为什么从 Redux 迁移到了 Mobx
Mobx 与 Redux 的性能对比
### 扩展阅读
## Mobx
Mobx 提供了一个类似 Vue 的响应式系统,相对 Redux 来说 Mobx 的架构更容易理解。 拿官方的图来看:
## RxJS
## 其他状态管理方案
## 扩展阅读