你说的react-redux整体方案的可维护性优势是存在的,但是我觉得你夸大了react的作用。这个优势主要是redux带来的。我们可以看到大量的react项目,业务逻辑也都是写在组件里面的,在组件里搞一大堆数据存取和计算,然后在组件里setState。这种玩法照样不可能带来任何好的架构。只有强制所有流程都走redux,才能达到你说的效果,但这又被用户诟病,redux成了个大框,啥都往里塞,导致后来dan澄清说local state is ok, you might not need redux. 所以,在react-redux体系下,事情也没那么理想。这很大程度上是因为redux强迫大家只能有一个中央state,所有状态都必须汇聚到这里来。如果你有个列表组件,那你就必须在redux里复制这个组件结构所需要的数据结构,使得redux事实上没有办法从ui具体设计中解耦出来。
vue生态在这方面基本是没什么建树的。ng在这方面的做法我觉得反而更靠谱些,就是引导大家把业务逻辑集中到service里,然后把可测性目标聚焦在service的设计上。不像redux,service不是全局单例的,是每一个组件都可以new的(其实是通过di系统注入的)。这就更合理一些。react的状态管理库其实一样可以这么搞。但是这都不是强制性的,只是框架和工具给用户进行了一些架构性的引导暗示而已。
我认为试图利用react vue ng这样的框架或者ui库来推行好的架构,本身就不彻底。前端在这方面和后端没啥区别,好的做法依然是靠架构规范来保证,而不是靠库来保证。
https://www.zhihu.com/question/468249924/answer/1968728853 我这个文章就是在讲这个事情,哪怕是前端项目,第一步照样应该是建立架构,把领域逻辑的模型单独拿出来设计,根据问题的性质,设计成oo风格的或者fp风格的模型,都可以。然后才是根据模型的风格来选取对应的响应化方案,以及ui库,完成model到view的简单映射。
换句话说,你起一个前端项目,和起一个其他项目一样,先要考虑的是,如果我要把这个逻辑做成一个“无头”系统,一个纯粹输入命令、输出数据的命令行工具,需要写哪些逻辑。这些就是你的业务逻辑。
如果你的模型里本身就需要类似useEffect watch的逻辑,不要依赖useEffect和watch这样
的框架api,而是自己用mitter之类的东西构造一个模型内部的sub/pub。
然后才是考虑你这个核心逻辑模块是要嵌入到一个网页里,还是客户端ui里,还是一个微服务的tcp或http endpoint里。如果是网页ui或客户端ui,你才考虑选择响应化方案和ui库。
比如,你的模型是基于class的,你就可以用vue3的reactive函数包一下,响应化之,然后接到vue库;或者可以用mobx的makeObservable处理一下,接到react库。如果你的模型是fp的,可能只能用useReduce作为媒介,接入原生react库。redux因为有上述单例state的限制,我的经验是不太适合作为接入媒介,至少会麻烦一些。
响应化和ui接入这些都是薄薄的一层,几乎不用测。可测性的成本都投入在业务model上。
你描述的react-redux架构,其实redux就扮演了这个领域逻辑model的角色。redux本身适合容纳fp风格的业务模型,并对接到react。不过如果你的业务模型的性质是典型的oo问题,用redux描述就比较繁琐。useReduce这样的hook倒是有潜力。
CTM书里提到了“最小表达力原则”,fp的表达力,如你所言,是小于oo的,如果一个问题用fp和oo来表达都很“自然”,那么应该倾向于用fp表达,这样reasoning的难度就较小。但我的体会是,大部分的真实项目,业务逻辑用包含可变状态的class来表达更“自然”。这种项目硬要对接为redux,抛开不变性带来的性能损失不谈,单就开发体验而言,写起来不那么顺畅。当然肯定不是不能写,函数早于oo被发明,oo没有发明之前人类照样写程序,就是稍微麻烦些罢了。
但是说到根本,要是做到了我文中提到的分离业务model在先,那么无论你后面用react,还是用vue,可测性可维护性就基本没区别了。可能区别就在于你前面讲到的那些时序稳定性的细节了。
【 在 eGust (十年) 的大作中提到: 】
: 几年前在版上吹 react 的时候,我表达过我的意思,oo 是工程师搞出来的东西,而 fp 是学院派出身,是有理论背景的。ng1 就算是工程师搞出来的最高成就了,而 react 一出则是彻底革了 ui 技术的命。
: 前面我说 react 用了俩 fp 概念其实不准确,实际上只有 pure function 一个核心概念,而 immutable 是由于 js 语言本身没带这能力才引入的。由于纯函数是个特别强的约束,表达能力反倒是极其有限的。而且正是由于这个特性,导致不得不对 side effect 进行特殊的考虑。这
: useEffect、useMemo、useReducer 等很多 api 都是先有了第三方库的生态,得到了社区的公认,react 又反过来引入的。比如复杂的状态管理也是经历了从 flux 到 redux 的过程,而 redux 为了解决 side effect 又引入了其它第三方的扩展。同理 redux-thunk 是工程师搞出来的
: ...................
--
修改:beep FROM 123.120.180.*
FROM 123.120.180.*