React 的界面与数据分离问题

React 生态庞大,没办法只能学一点。第一段学完就有一个根本性的问题了:它竟然把数据、业务逻辑和界面混在一起,组件变成了有“业务状态”的组件,这就意味着UI和业务绑定了。而这种糟糕的设计是 d2js (前端库)从一开始就避免的。

React 发明了 react hooks 之类高级概念进行挽救:

使用React Hooks代替类的6大理由_语言 & 开发_Dilantha Prasanjith_InfoQ精选文章

还发明了“关注点分离”这样的高深莫测的名词。用Hooks实现关注点分离 | Deathdealer's Blog

模仿 react 的 Jetpack Compose 也想明白了这点,把界面输出变成了一套数据->UI 的渲染函数。

但是渲染函数也不一定合理,好好的二阶的面向对象坍缩成了一阶的函数,其实界面和数据确实应该有一个关系。界面组件引用数据,界面组件有一个位子为数据预留,这本来是很合理的,但 React 把"数据"的范围搞的太宽泛了,它的 State 支持任意 js 数据,这导致用户要手工调用 setState 来实现刷新。

在 d2js 中,数据不需要知道组件,数据更新后组件可以总刷新, 而在 react 中,必须找到组件以调用组件的 setState 进行刷新。的确,react 渲染函数中的组件是匿名的,不需要“摸”它们,但“这个组件”本身不是,需要摸到它才能进行 render。react hook 化解了这个危机,变成了一组渲染函数,最终效果和 d2js 有点相似,但 useState 这样的写法还是不如向上游提出要求。

react 的 state 不应是任意 js 对象,应当要求数据支持变更事件,界面组件订阅数据变更事件,从而重绘UI。对单元测试来说给数据挂变更侦听也是更方便的做法。

另一个问题是,React 的组件中真正的UI元素都是通过 render 给出的,即使是复合组件也不是复合的,子元素不是组件的成员,子元素无法抓获,父元素的树也没有它们的树的地位,所以也无法操作它们,当然,要说完全无法抓获也不对,通过给它起个id什么的也能抓获,但是它不是一种复合,这很奇怪。

React 的解释是这种 UI 元素并不属于用户所给的UI元素,比如有一个容器组件,它在使用时用户给定的内容组件,才是 react 所认可的子元素,而渲染出图的 ui 元素,不能属于子元素。这种做法其实很费解,react 最大的优势是 vdom,vdom 的本质是dom 元素交给托管状态的diff函数,为了一些可托管状态的子元素而导致子元素无法把控,让人难以理解。

复合行为诡异,不支持继承,说明 React 的设计可能是错的,它不是在搭UI的积木,而是在搞状态化的渲染函数,这种对UI元素漠然的UI思想似不及 moulecule。

posted @ 2022-06-20 16:00  Inshua  阅读(348)  评论(0编辑  收藏  举报