fe-hunter icon indicating copy to clipboard operation
fe-hunter copied to clipboard

如何选择React状态管理库?

Open BetaSu opened this issue 3 years ago • 6 comments
trafficstars

发生问题的场景

小明刚开始使用React,面对众多的状态管理库(Redux、MobX、Recoil、Zustand、Jotai、valtio...)他有点不知所措

需要解决的问题

你能从以下角度帮他分析如何做状态管理库的选型么?

  1. 从业务规模角度分析(自己的练手项目、几个人参与的一次性的小项目、团队参与的长期维护的大项目...)
  2. 从管理的状态类型分析(与用户交互相关的状态、服务端请求回的数据...)
  3. 从应用类型分析(普通活动页、富文本编辑器...)
  4. 其他角度(比如普及度、上手难度)

最佳答案评选标准

请从以上角度有条理作答,细致而全面的答案是加分项

最佳答案

悬赏中,欢迎作答...

答题同学须知

  • 答题规范:请在一次评论中完成作答,后续修改也请编辑该评论,而不是追加新的评论

  • 评选标准:最佳答案由围观同学的 👍 和卡颂共同决定

  • 评选时间:一般是问题发布24小时后评选,如果问题发布当天回答数较少,问题悬赏金额可能增加,同时悬赏时间也会增加

围观同学须知

  • 对于你满意的答案,请不要吝惜你的 👍,这是评选最佳答案的依据

  • 非答题的评论会被删除,问题相关讨论请在赏金猎人群中进行

BetaSu avatar Mar 30 '22 01:03 BetaSu

(重点提示一下:有意思的是,Zustand、Jotai、valtio 基本都出自dai-shi 大佬之手,嘿嘿,发现什么了没,也许你顺着这条线索就已经可以找到题目的答案了,我下面的文字也不需要看了)

最近刚好在解决项目里面滥用 redux 的问题,来凑一下热闹。先声明一下,我不打算直接回答题目本身,以下所有观点也仅代表目前的一些杂乱的思绪,文字看起来也会比较乱,但也都是来自实际的业务一线的一些思考,也不一定逻辑正确。

怎么说呢,这个问题需要写一篇很长很长的文章了,现版本的 react 的状态管理不能一概而论认为该采用什么第三方库,而是要回归本质的思考状态,先简单描述一下吧(以下只针对 function component,class component 也该退出历史舞台了):

1、要搞懂这个问题,首先要去深刻理解 hook 的 useState,以及 function component 的 re-render 机制(这个很重要,因为状态管理必须围绕着这个展开,也就是状态的更新怎么触发组件的更新),需要注意的是,function component 和 react 以前的 class component 从理念上是有很大差别的,包括其组件的 re-render 机制。

2、要搞懂 mutable 和 immutable,是的,这特别重要,因为现在版本的 react 处处强调 immutable 的重要性,包括 state,props,context,useEffect、useCallBack 的 deps 等。我记得 Dan Abramov 在字节的采访中说过:Vue 在不断探索我们可以用 mutability 做什么,而 React 在不断探索 immutability 能够做到的事。(ps:redux 是 immutable 的,mobx 是 mutable 的,同时必须得安利一下 immer 这个库:Immer simplifies handling immutable data structures)

3、搞懂 Context API,和它的适用场景,还有 Context 用作状态管理的话,其实是不太够的,目前 Context 存在的问题:如果用的不合理会引起很多不必要的渲染,比如 Context 的 value 用了大对象。然后理解什么场景该用 state,什么场景该用 Context。虽然 Context 有不足的地方,但有些状态管理库底层会用 Context,或者在使用层面会涉及到怎么和 Context 结合,搞清楚 Context API 的原理能帮助你很好的理解其他的状态管理库。知乎上的这个问题可以读一下,这个回答下面的几位大佬其实已经讲了 Context 的局限性,还有怎么合理的使用和优化它,感兴趣的可以细读一下 https://www.zhihu.com/question/450047614 (当然了,有人说用 Context + useReducer 也可以实现状态管理,其实是可以的,没毛病,但是呢,由于 Context 的局限性,其实这种方案也是不太够的,用的不好依然有不必要的渲染的问题。具体看我上面贴出来的知乎的链接里的讨论)

4、选择合适的数据结构去定义state(在react里面一定要注意 immutable data structure 的更新问题),学会合理组织 state,这一点也特别重要,具体可以看 react 新文档的这一节 https://beta.reactjs.org/learn/choosing-the-state-structure 这一点告诉我们,数据结构还是重要啊

5、学会自定义 hook 去抽离通用的逻辑,然后知道什么场景该抽离 hook

6、要合理的封装组件(特别是要分清组件的 state 和 props 的职责,这个也许需要大量的实践,但你可以从软件的 API 设计的角度出发去考虑)

7、学会处理异步数据请求,具体可以看这篇文章 https://www.robinwieruch.de/react-hooks-fetch-data/

8、关于 hook 背景下的状态管理的一些问题,推荐关注一下dai-shi 大佬的主页和他的博客,他是是 use-context-selector、react-tracked、jotai、zustand、valtio的作者,同时对于状态已经状态管理有很深的理解(别误会,不是列出一堆东西,让大家再次陷入技术选型的漩涡,而是从大佬的作品和思考中获得启发,从而得到自己的理解)

ok,深刻搞清楚了以上的这些点,然后才会来到我们的状态管理。为什么这样讲呢,因为很多场景其实要合理的拆分组件,合理的去定义和组织组件的 state 和 props,合理的抽离 hook,合理的处理好异步数据,这才是做好状态管理的前提,而不是一上来就什么都塞到集中式的 Store 里面去。而且从我这几年看到的实际项目中的场景来看,确实是很多人没搞清楚这些,然后把状态一股脑的塞到 redux 里面,这样就带来了很多问题了。这些问题包含了 redux 文件的膨胀和繁杂的模版代码,state 和 props 职责的不清晰,异步数据的处理的混乱,state 的数据结构使用的不合理,从而导致项目充斥着各种胶水代码,等等等。当然了,就算不用 redux,用其他的库也是一样的。

如果对以上的概念不熟悉的,推荐大家好好认真的读一下 react 的新文档:https://beta.reactjs.org 如果完整的读一遍,并且把文档的每个 demo 都好好跑一遍,应该会有不一样的认识

然后我们的焦点才来到状态管理的问题,什么 redux,mobx,Recoil,redux toolkit,hox,zustand 等等等。。。这个讲起来又要涉及到很多东西了,比如 1、状态机,单向数据流,响应式, immutable和mutable,函数式和oop,原子化,集中式状态管理,发布订阅者模式(是的,题目里列出来的这几个库,要搞清楚它们之间的区别都或多或少的涉及到这些乱七八糟的概念) 2、什么场景应该用内聚的 state,什么场景仅仅用 Context 就可以了,什么逻辑该抽离成 hook(自定义的hook是可以包含状态的),全局的状态和局部组件的状态该怎么做。 3、状态和行为怎么合理的一起封装,然后状态更新后怎么通知组件的更新 4、怎么处理异步 5、状态管理基本都围绕着这些问题展开,理清楚之后,才能做到手中无剑,心中也无剑,回归初心,化繁为简在不同的业务场景选择合适的方式(因为有些状态管理库的模版代码或者 API 真的很多,非常很容易让人迷失其中) 6、甚至你可以封装自己的状态管理库 7、等等等。。。

好了,废话有点多,随性而写的,可能文字也比较乱,我也没有给出答案(因为我自己也还差一些才能把思路捋清楚),但其实我是希望大家能回归本质的去思考状态和状态管理,而不是迷失在选择哪一个库,或者武断的认为就该怎样和不该怎样,这世界有时候没有标准答案,只有认知的不一样,对生活的理解不同,就会有不一样的人生,无所谓对错,但确实存在着特定的场景下某种方式也许更合理。

先占个坑位,如果有大佬愿意提高一下悬赏金额,我可以考虑抽空把更详细的文章(1w字以上吧)写出来,由浅入深的讲讲这些问题(最近实在太多事情要做了,穷啊,没钱没动力码字啊)


2022.5.7更新: 最近有不少同事问 recoil、jotai ,和 mobx、redux 怎么选择。怎么说呢,原子化和状态聚合是两种不同的方式,而且完全可以共存。recoil、jotai 的这种原子化的方式,api 类似 useState,容易上手。而 mobx、redux 的这种叫状态聚合的方式。如果你的应用是数据驱动的,或者对数据结构要求比较高的,那么状态原子化是不够的,必然要走到状态聚合的方式上去。而 redux 和 mobx 呢,我个人是更推荐 mobx,或者类 mobx 的方案,原因很简单,mobx 对多样性的自定义的数据结构兼容更好,如果你是个有追求的程序员,那么在复杂的数据驱动型的应用里面,必然会涉及到很多自定义的数据结构。而且在 js 里面, mutable 的数据结构的代码,天然就比 immutable 的数据结构的代码更清晰,也更容易理解(当然了,你也可以借助 immer 来降低 immutable 数据结构的操作成本,但依然是要啰嗦一些)

kairos1874 avatar Mar 31 '22 05:03 kairos1874

https://zhuanlan.zhihu.com/p/475785123 这位博主总结的很好

handsomeCarl avatar Apr 01 '22 09:04 handsomeCarl

https://zhuanlan.zhihu.com/p/475785123 这位博主总结的很好

当他说Recoil难用的时候,这篇文章就已经被 Pass

bigbigDreamer avatar Apr 02 '22 01:04 bigbigDreamer

  1. redux和react-redux,老牌react状态管理,但操作麻烦,发送异步请求需要借助中间件(react-thunk或者react-saga),不能直接发送异步请求,没有提供命名空间,各个模块需要注意命名,内部原理为发布订阅,有点消耗性能,提供了类组件和函数组件两种用法,适合入门学习。
  2. dva,基于react-saga封装,提供了redux所有操作,并且集成了异步请求和命名空间,不过需要会es6迭代器语法或者已经会react-saga的开发者,如果你的项目是采用umi,umi自带dva,将是最好的选择。不过个人觉得dva和vuex很像,如果你是一名vue开发者,相信dva很快能上手。适合大型项目,有结构的组织你的状态管理。
  3. recoil,facebook新推出的状态管理库。上手简单,主要api也就是atom和selector两个,而且主打高性能,提供每个数据唯一key,避免数据污染,不过目前只支持函数组件,不支持类组件。

LadyChatterleyLover avatar Apr 29 '22 05:04 LadyChatterleyLover

https://juejin.cn/post/6986816997329731614 可以参考下

specialbiscuit avatar Sep 30 '22 07:09 specialbiscuit

这是来自QQ邮箱的假期自动回复邮件。   您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。

imondo avatar Sep 30 '22 07:09 imondo