【 在 eGust (十年) 的大作中提到: 】
: 标 题: Re: 对比 vue,reactjs 就是个笑话!
: 发信站: 水木社区 (Wed Jun 30 09:19:44 2021), 站内
:
: react 其实只用了俩核心 fp 概念,一个是 pure function,另外一个是 immutable。延伸出来就是数据的单向流动,hooks 的 getter/setter 设计跟 input/select 完全是一样的。这种设计的结果就是,react 里的 state 就是 single source of truth。而每次由当前的 state 和一个参数(action)生成一个新的 state 的过程也非常简单,由于是纯函数,给定确定的 state 和 action 每次都能保证产生相同的结果。这其实也是 fp 的优势,非常容易写 unittest。
:
所以现在回复一下你这个第二段,我觉得讲得不对,和上面第一段也没有因果关系。
web ui肯定是个有大量可变状态和副作用的系统,这是避免不了的。你第一段说 react 能够用纯函数和不可变性来写业务逻辑,其实只是它自己把所有的可变性都给集中在框架内部的处理环节了,留给用户的部分迫使用户写成纯函数。
对于用户来说,这有得有失。很多业务逻辑其实用 OOP 风格写起来很合适,但是非要写成一组一组的纯函数,一方面写起来有点麻烦(幸亏现在有 immer),另一方面,就是那个典型的问题,性能低下。人家本来就是冯诺依曼结构的机器,都是cpu加可变存储单元,结果你非要每个变更都把整个状态树都重做一遍,然后再全树 diff,reconcile,中间做了无数无用功。react 的源码比 vue 复杂无数倍,接下来的 cocurrent mode 肯定还要更复杂。从宏观设计上看,在 UI 这么典型的 OO 领域,在 js 这种这么方便做 proxy 的语言里,非要硬拗 FP,我不觉得这是个好的设计决策。
得到的好处呢?其实就是可测性好。。。但 OOP 风格的模型也不见得可测性不好,只要依赖反转做到位,坚持面向接口编程,万物都可以 mock。mock 这东西,FP 测试也避免不了的。
然后说到下面第二段,watch 并不是因为 vue 采用了双向数据绑定才不得不引入的。这个东西和双向数据绑定毫无关系。而且我认为所谓双向数据绑定,是个普遍的误解。vue 和
ng 和 react 一样,都是组件树自上而下单向数据流,只是在 form 组件这一个小地方,
vue 和 ng 提供了一个语法糖,把一个向下的参数传递,和一个向上的事件传递,允许用户写成一个 v-model 或者 [(ng-model)] 简写,仅此而已。如果 react 愿意,分分钟也可以这么做。在数据流的结构这方面,三大框架是非常一致的,组件树的数据肯定是从上往下,然后允许子树上新增局部数据,继续往下传。如果有往上传的需求,都是通过事件来做。
回到 watch。上面说过,UI 系统不可能避免副作用,副作用有很多种,前端框架 react vue 本身只是帮你集中处理了 DOM 变化的副作用,但还有很多很多其他的副作用,是必须用类似 watch 的东西来写的。react 从前有 componentWillReceiveProps,现在有 useEffect,其实就是和 watch 一样的东西。现在大家写 react hooks,一个很大的吐槽就是如你下面所说,useEffect 里面的逻辑套逻辑,你触发我,我触发它,层次多了就乱了。和你说的问题是一样的。这也不是前端框架独有的问题。凡是 pub-sub 结构的体系,都是一样的问题。
倒是因为 useEffect 还需要用户手动写依赖项,导致 effect 嵌套的时候,会频繁遗漏依赖项,导致更多 bug。react 官方说,今后会提供一个静态分析工具,自动给用户填 effect 依赖。。。
最后,咱们刚才做实验的 watcher 触发顺序问题,也是一样的。react 只是把真实修改
state 的地方集中到它内部来执行了,该有顺序问题还是会有顺序问题,毕竟还是在一个
cpu 核心上跑的代码。
: ng1/vue 的双向数据绑定表面上看起来非常直观,vue 的 data 看起来也是跟 state 一样的概念。但这种设计却不得不引入 watch,而它又其实引发了许多问题。首先 watcher 里面可能会再更新 data,而又可能触发其它的 watcher,这就导致了数据的更新流程非常复杂,不像 newState = reduce(oldState, action) 那么简单。其次,多个 watchers 监视同一个数据的变动也是很难避免的,那么它们触发的顺序就变成了一件非常微妙的事情,很可能由于触发顺序的不同而产生不同的结果。另外,watcher 里面依赖了哪些外部的变量也是非常难预测的,导致的结果就完全相同 data 初始结果,同样的事件可能导致不同的最终值。所以如果没设计好的话,很容易把 unittest 的依赖关系搞的非常复杂,很难实现。
:
: 总体上,我是更倾向 react + hooks 的,因为 fp 的条条框框在那里绕不过去,迫使项目的设计差不了,用起来是个先苦后甜的过程。vue 容易上手,副作用就是项目上设计起来非常容易放飞自我,最后的坑不比 jquery 的项目少。
:
: 【 在 beep (菜M.喵星耗子) 的大作中提到: 】
: : class组件,和hooks组件,各有各的复杂,都很麻烦。本质上是因为react采取了一个奇葩的响应式方案,就是对状态根对象做简单的引用比较。为了这个,弄出一堆fp不可变的东西来,不管咋弄心智负担都不小。
: : 这方面我还是觉得vue mobx这种proxy式的响应式方案比较靠谱,也切合现在业务逻辑一般都用class oop来写的实际情况。proxy式的响应方案,虽然也要注意不能丢失引用,但是规则还是比较简单的,只要记住永远要用a.b就可以,不能没有中间那个点。
: : 前面有人提到被toRef toRaw这些搞晕了,其实这些都是处理特殊情况的边缘api。正常只要记住上面的规则,会用ref reactive,知道computed返回的是个ref,就可以干活了。
: : ...................
:
: --
:
: ※ 来源:·水木社区 mysmth.net·[FROM: 115.188.133.*]
--
修改:beep FROM 123.120.168.*
FROM 123.120.168.*