组长让我把所有state都放Redux里

4,539 阅读4分钟

大家好,我是卡颂。

在我们React进阶源码群里,除了React外,状态管理是最常讨论的话题。

诡异的是,有多个群友说过类似的话:

他的同事/组长/领导...让他把所有state都放在Redux/Mobx...里

他们觉得不对,又不知道如何反驳。

今天我们来聊聊ReduxMobx等状态管理库和ReactVue等视图库之间的关系,希望能解决以上困惑。

产品的核心竞争力

如果你在电梯里遇到大领导,他问你:

小x,你们最近在做什么功能?

在电梯到达楼层前这短短2分钟,你该如何向大领导描述你们正在开发的功能呢?

我想你一定会介绍功能的大体逻辑,而不会聊功能里某个按钮的具体交互逻辑吧?

你会聊逻辑,而不是交互。因为逻辑是最重要的。

接下来我们通过一个小故事了解逻辑交互的关系。

逻辑与交互的关系

一天,老板让你开发文件上传功能。

开发过程其实就是处理文件上传这一领域相关的各种状态之间的关系(比如上传进度是否出错...)。

这部分状态,我们称为领域状态

逻辑开发完后,你基于各种领域状态编写单元测试

为了快速上线验证该功能是否有人用,你直接将其作为CLI工具发布。

几天后,经过数据验证,发现功能很受欢迎。于是你选择React作为视图库,基于之前的逻辑开发视图交互。

开发视图交互过程中需要处理视图相关各种状态(比如loading显隐打开关闭状态...)。

这部分状态,我们称为视图状态

可见,一款功能完备的产品包含领域状态视图状态。前者是必须的,后者是可选的。

视图库中的状态

说回ReactVue这样的视图库。

由于大部分视图库以组件作为模块边界,所以很自然的,领域状态视图状态被分割到不同组件中,但他们被分割的方式是完全不同的。

举个例子,一个完整的应用可以划分为很多组件:

视图状态角度来看这些组件:

对比上下两张图,组件1(黄色与绿色)大小一致,代表这是个交互逻辑自洽的纯组件(比如一个开关),他的交互逻辑不依赖其他组件。

一个开关

除了组件1,更多组件需要与其他组件形成大小互补,这代表他们的交互逻辑互相影响。

比如组件5的长宽受组件2、组件6、组件8影响,可能代表:组件5是个提示框,他是否弹出受2、6、8影响。

我们再从领域状态(蓝色部分)角度来看这些组件:

整个应用的逻辑分散在不同组件中,可能组件1的didMount回调中有一部分逻辑,组件3的useEffect回调中有一部分逻辑。

由于组件5是个提示框,只有提示效果,所以他不包含应用运转所必需的逻辑(即领域状态)。

什么时候使用状态管理

回到开篇,什么样的state(状态)应该放在状态管理里?

对于视图状态

  • 状态自洽的组件自己管理状态(如组件1)

  • 状态互相之间有影响的组件(如5与2、6、8)根据应用复杂度、组件间跨度决定

如果组件跨度比较近(如是兄弟关系),则公共状态可以提升到共同父组件。

如果组件跨度较远且应用不复杂,可以提升到共同的Context中。

如果应用复杂,再考虑状态管理方案。

对于领域状态,由于其天生以碎片形式分布在不同组件中,所以:

  • 简单的小应用可以任其分布在组件中,或者提升到共同的Context

  • 其他情况推荐用状态管理方案

甚至,对于领域状态中的子领域,可以在有状态管理方案的基础上再抽象出来单独处理。

比如对于服务端请求的数据这一领域状态,其性质更类似于缓存,在React中可以使用SWRReact Query处理。

总结

本文我们聊了状态的分类 —— 领域状态视图状态,对于这两种状态根据其特性有不同处理方案。

虽然一股脑将所有状态都交给Redux处理不是不行,但势必对项目的可读性、性能、扩展性造成影响。

学完本文能够说服同事/组长/领导最好。如果对方执意要Redux一把梭,对待这种执(憨)着(憨)的人,牢记四字箴言: