大家好,我是卡颂。
在我们React
进阶源码群里,除了React
外,「状态管理」是最常讨论的话题。
诡异的是,有多个群友说过类似的话:
他的同事/组长/领导...让他把所有state都放在Redux/Mobx...里
他们觉得不对,又不知道如何反驳。
今天我们来聊聊Redux
、Mobx
等状态管理库和React
、Vue
等视图库之间的关系,希望能解决以上困惑。
产品的核心竞争力
如果你在电梯里遇到大领导,他问你:
小x,你们最近在做什么功能?
在电梯到达楼层前这短短2分钟,你该如何向大领导描述你们正在开发的功能呢?
我想你一定会介绍功能的大体逻辑,而不会聊功能里某个按钮的具体交互逻辑吧?
你会聊逻辑
,而不是交互
。因为逻辑
是最重要的。
接下来我们通过一个小故事了解逻辑
与交互
的关系。
逻辑与交互的关系
一天,老板让你开发文件上传功能。
开发过程其实就是处理「文件上传」这一领域相关的各种「状态」之间的关系(比如上传进度
、是否出错
...)。
这部分状态,我们称为「领域状态」。
逻辑开发完后,你基于各种「领域状态」编写「单元测试」。
为了快速上线验证该功能是否有人用,你直接将其作为CLI
工具发布。
几天后,经过数据验证,发现功能很受欢迎。于是你选择React
作为视图库,基于之前的逻辑开发视图交互。
开发视图交互过程中需要处理视图相关各种「状态」(比如loading显隐
、打开关闭状态
...)。
这部分状态,我们称为「视图状态」。
可见,一款功能完备的产品包含「领域状态」与「视图状态」。前者是必须的,后者是可选的。
视图库中的状态
说回React
、Vue
这样的视图库。
由于大部分视图库以「组件」作为模块边界,所以很自然的,「领域状态」与「视图状态」被分割到不同组件中,但他们被分割的方式是完全不同的。
举个例子,一个完整的应用可以划分为很多组件:
从「视图状态」角度来看这些组件:
对比上下两张图,组件1(黄色与绿色)大小一致,代表这是个交互逻辑自洽的纯组件(比如一个开关),他的交互逻辑不依赖其他组件。
一个开关
除了组件1,更多组件需要与其他组件形成大小互补,这代表他们的交互逻辑互相影响。
比如组件5的长宽受组件2、组件6、组件8影响,可能代表:组件5是个提示框,他是否弹出受2、6、8影响。
我们再从「领域状态」(蓝色部分)角度来看这些组件:
整个应用的逻辑分散在不同组件中,可能组件1的didMount
回调中有一部分逻辑,组件3的useEffect
回调中有一部分逻辑。
由于组件5是个提示框,只有提示效果,所以他不包含应用运转所必需的逻辑(即「领域状态」)。
什么时候使用状态管理
回到开篇,什么样的state
(状态)应该放在状态管理里?
对于「视图状态」:
- 状态自洽的组件自己管理状态(如组件1)
- 状态互相之间有影响的组件(如5与2、6、8)根据应用复杂度、组件间跨度决定
如果组件跨度比较近(如是兄弟关系),则公共状态可以提升到共同父组件。
如果组件跨度较远且应用不复杂,可以提升到共同的Context
中。
如果应用复杂,再考虑状态管理方案。
对于「领域状态」,由于其天生以碎片形式分布在不同组件中,所以:
- 简单的小应用可以任其分布在组件中,或者提升到共同的
Context
中 - 其他情况推荐用状态管理方案
甚至,对于「领域状态」中的子领域,可以在有「状态管理方案」的基础上再抽象出来单独处理。
比如对于「服务端请求的数据」这一「领域状态」,其性质更类似于「缓存」,在React
中可以使用SWR
或React Query
处理。
总结
本文我们聊了状态的分类 —— 领域状态
与视图状态
,对于这两种状态根据其特性有不同处理方案。
虽然一股脑将所有状态都交给Redux
处理不是不行,但势必对项目的可读性、性能、扩展性造成影响。
学完本文能够说服同事/组长/领导最好。如果对方执意要Redux
一把梭,对待这种执(憨)着(憨)的人,牢记四字箴言:
公众号:前端食堂
知乎:童欧巴
掘金:童欧巴
这是一个终身学习的男人,他在坚持自己热爱的事情,欢迎你加入前端食堂,和这个男人一起开心的变胖~
“如果你觉得读了本文有收获的话可以点个在看让我看到。阅读过程中有任何问题、想法或者感触也欢迎你在下方留言,也可以在后台回复加群进入食堂的交流群。 沟通创造价值,分享带来快乐。也欢迎你分享给身边有需要的同学,利他就是最好的利己。 ”