2015 年 7 月编辑:目前最有前途的基于不变性的框架是Redux!看一看!它不像 Om 那样使用游标(Om Next 也不使用游标)。
游标并不是真正可扩展的,尽管使用了下面描述的 CQRS 原则,但它仍然在组件中创建了太多的样板,难以维护,并且当您想在现有应用程序中移动组件时会增加摩擦。
此外,许多开发人员不清楚何时使用和不使用游标,我看到开发人员在不应该使用的地方使用游标,这使得组件的可重用性不如采用简单props的组件。
Redux 使用connect()
, 并清楚地解释了何时使用它(容器组件),何时不使用(无状态/可重用组件)。它解决了将光标向下传递到树的样板问题,并且在没有太多妥协的情况下表现出色。
我已经写过不使用这里的缺点connect()
尽管不再使用游标,但我的大部分答案仍然有效恕我直言
我自己在我们的启动内部框架atom-react 中完成的
JS 中的一些替代方案是Morearty、React-cursors、Omniscient或Baobab
当时还没有immutable-js
,我也没有做迁移,仍然使用纯JS对象(冻结)。
我不认为使用持久数据结构库真的是必需的,除非你有非常大的列表,你经常修改/复制。当您注意到性能问题作为优化时,您可以使用这些项目,但似乎不需要实现 Om 的概念来利用shouldComponentUpdate
. 有趣的一件事是immutable-js
关于批处理突变的部分。但无论如何,我仍然认为这是优化而不是使用 Om 的概念在 React 中获得非常好的性能的核心先决条件。
您可以在此处找到我们的开源代码:
它具有 Clojurescript Atom的概念,它是对不可变对象(用DeepFreeze冻结)的可交换引用。它还具有事务的概念,以防您希望以原子方式更新状态的多个部分。并且您可以监听 Atom 更改(事务结束)以触发 React 渲染。
它有cursor的概念,就像在 Om 中一样(就像一个功能镜头)。它允许组件能够呈现状态,但也可以轻松修改它。这对于表单很方便,因为您可以直接链接到游标以进行 2 路数据绑定:
<input type="text" valueLink={this.linkCursor(myCursor)}/>
它具有纯渲染的概念,开箱即用优化,就像在 Om中一样
与 Om 的区别:
- 没有本地状态(this.setState(o) 被禁止)
在 Atom-React 组件中,您不能拥有本地组件状态。所有状态都存储在 React 之外。除非您有现有 Js 库的集成需求(您仍然可以使用常规的 React 类),否则您将所有状态存储在 Atom 中(即使是异步/加载值),并且整个应用程序从主要的 React 组件重新呈现自身。React 只是一个模板引擎,非常高效,可以将 JSON 状态转换为 DOM。我觉得这非常方便,因为我可以在每次渲染时记录当前的 Atom 状态,然后调试渲染代码非常容易。由于开箱即用,shouldComponentUpdate
它足够快,我什至可以在用户在文本输入上按下新的键盘键或用鼠标悬停按钮时重新渲染完整的应用程序。甚至在手机上!
- 管理状态的意见方法(受 CQRS/EventSourcing 和 Flux 启发)
Atom-React 有一种非常自以为是的方式来管理受Flux和CQRS启发的状态。一旦您拥有 React 之外的所有状态,并且您有一种将 JSON 状态转换为 DOM 的有效方法,您就会发现剩下的困难是管理您的 JSON 状态。
其中遇到的一些困难是:
- 如何处理异步值
- 如何处理需要 DOM 更改的视觉效果(例如鼠标悬停或焦点)
- 如何组织您的状态,以便在大型团队中进行扩展
- 在哪里触发 ajax 请求。
所以我最终得到了 Store 的概念,受到Facebook Flux 架构的启发。关键是我真的不喜欢 Flux 存储实际上可以依赖另一个的事实,需要通过复杂的调度程序来编排操作。您最终必须了解多个商店的状态才能呈现它们。
在 Atom-React 中,Store 只是 Atom 持有的状态中的一个“保留名称空间”。
所以我更喜欢从应用程序中发生的事件流更新所有商店。每个 store 都是独立的,并且不访问其他 store 的数据(就像在 CQRS 架构中一样,其中组件接收完全相同的事件,托管在不同的机器上,并按照自己的意愿管理自己的状态)。这使得维护更容易,因为当您开发新组件时,您只需要了解一个商店的状态。这以某种方式导致数据重复,因为现在在某些情况下,多个商店可能必须保留相同的数据(例如,在 SPA 上,您可能希望在应用程序的许多地方都使用当前用户 ID)。但是如果 2 个商店将同一个对象置于它们的状态(来自一个事件),这实际上不会消耗任何额外的数据,因为这仍然是 1 个对象,
要了解这种选择背后的原因,您可以阅读 CQRS 领导者 Udi Dahan、The Fallacy Of ReUse和其他有关自治组件的博客文章。
因此,存储只是一段代码,用于接收事件并更新其在 Atom 中的命名空间状态。
这将状态管理的复杂性移到了另一层。现在最难的是精确定义哪些是您的应用程序事件。
请注意,该项目仍然非常不稳定且未记录/未经过充分测试。但是我们已经在这里使用它并取得了巨大的成功。如果你想讨论它或贡献,你可以在 IRC 上联系我:Sebastien-L
在#reactjs
.
这就是用这个框架开发 SPA 的感觉。每次渲染时,在调试模式下,你有:
- 将 JSON 转换为虚拟 DOM 并将其应用于真实 DOM 所花费的时间。
- 记录状态以帮助您调试应用程序
- 浪费时间感谢
React.addons.Perf
- 与先前状态相比的路径差异,可轻松了解发生了什么变化
检查此屏幕截图:
这种框架能带来的一些优点我还没有深入探讨过:
您确实内置了撤消/重做功能(这在我真正的生产应用程序中开箱即用,而不仅仅是 TodoMVC)。然而恕我直言,许多应用程序中的大多数操作实际上都会对服务器产生副作用,因此将 UI 反转到之前的状态并不总是有意义的,因为之前的状态会过时
您可以记录状态快照,并将它们加载到另一个浏览器中。CircleCI 在这个视频中展示了这一点
您可以以 JSON 格式录制用户会话的“视频”,将它们发送到您的后端服务器进行调试或重播视频。您可以将用户会话实时流式传输到另一个浏览器以获得用户帮助(或监视以检查用户的实时 UX 行为)。发送状态可能非常昂贵,但像 Avro 这样的格式可能会有所帮助。或者,如果您的应用程序事件流是可序列化的,您可以简单地流式传输这些事件。我已经在框架中轻松实现了它,它可以在我的生产应用程序中运行(只是为了好玩,它还没有向后端传输任何内容)
可以像在 ELM 中一样使时间旅行调试成为可能
我为那些感兴趣的人制作了一个关于“在 JSON 中记录用户会话”功能的视频。