Om在JavaScript中是什么意思?

43

我越来越喜欢 David Nolen 的 Om 库

我想在我们团队中构建一个不太大的Web应用,但我无法说服我的队友们转向 ClojureScript。

有没有一种方法可以使用 Om 中使用的原则,但用 JavaScript 构建应用程序呢?

我正在考虑这样的东西:

  1. immutable-jsmori 用于不可变数据结构
  2. js-csp 用于CSP
  3. 一个普通的Javascript对象用于 app-state 原子
  4. immutable-js 用于 cursors
  5. 某些东西用于跟踪 app-state 并根据 cursors 发送通知

我在挣扎上述的第5点。

是否有人尝试过这个领域或有任何建议?也许有人尝试过使用 immutable-js 构建 react.js 应用程序?

2个回答

60
2015年7月编辑:目前基于不变性最有前途的框架是Redux!它并不像Om那样使用cursors(Om Next也不使用cursors)。

尽管使用了下面描述的CQRS原则,但cursors实际上并不具备可扩展性,它仍会在组件中创建太多样板代码,这很难维护,并且在想要在现有应用程序中移动组件时增加了摩擦。

此外,对于许多开发人员来说,在何时使用和不使用cursors并不清楚,我看到开发人员在不应该使用cursors的地方使用cursors,使得组件不够可重用,而简单传递props的组件则更加可重用。

Redux使用connect(),并明确解释了何时使用它(容器组件),以及何时不使用它(无状态/可重用组件)。它解决了将cursors向下传递到树中的样板问题,并且在没有太多妥协的情况下表现出色。

我已经写过不使用connect()的缺点here

尽管不再使用cursors,但我认为我的答案大部分仍然有效。


我已经在我们创业公司的内部框架atom-react中完成了它。
JS中的一些替代品是Morearty, React-cursors, OmniscientBaobab
当时还没有immutable-js,我没有进行迁移,仍然使用普通的JS对象(被冻结)。
我认为,除非您经常修改/复制非常大的列表,否则不需要使用持久数据结构库。当您注意到性能问题时,可以将这些项目用作优化,但似乎并不需要实现Om的概念以利用shouldComponentUpdate。一个有趣的事情是immutable-js中关于批量突变的部分。但无论如何,我仍然认为这是优化,不是使用Om的概念来实现React并获得非常良好的性能所必需的核心先决条件。
您可以在此处找到我们的开源代码:
它具有Clojurescript Atom的概念,这是对不可变对象(使用DeepFreeze冻结)的可交换引用。它还具有事务的概念,以便可以原子地更新状态的多个部分。您可以监听Atom更改(事务结束)以触发React渲染。
它具有cursor的概念,就像Om中的功能镜头。 它允许组件能够呈现状态,也可以轻松修改状态。 这对表单非常方便,因为您可以直接链接到光标以进行双向数据绑定:
<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状态。
遇到的一些困难包括:
1. 如何处理异步值 2. 如何处理需要DOM更改的视觉效果(例如鼠标悬停或焦点) 3. 如何组织你的状态,使其在大型团队中扩展 4. 在哪里触发ajax请求 所以我想到了Store的概念,受到Facebook Flux architecture的启发。问题在于我真的不喜欢Flux store实际上可能依赖于另一个store,需要通过复杂的dispatcher协调操作。你最终不得不理解多个store的状态才能渲染它们。
在Atom-React中,Store只是Atom保留命名空间内的状态。
我更喜欢所有商店都从应用程序中发生的事件流更新。每个商店都是独立的,并且不访问其他商店的数据(就像在CQRS架构中一样,组件接收完全相同的事件,托管在不同的机器上,并根据自己的意愿管理其自己的状态)。这使得维护更容易,因为当您开发新组件时,您只需要了解一个存储的状态即可。这在某种程度上会导致数据重复,因为现在多个商店在某些情况下可能必须保留相同的数据(例如,在SPA上,您可能希望在应用程序的许多位置中都有当前用户ID)。但是,如果2个商店将相同的对象放入其状态中(来自事件),则实际上不会消耗任何额外的数据,因为这仍然是1个对象,在2个不同的商店中引用两次。
要了解此选择背后的原因,可以阅读CQRS领袖Udi Dahan的博客文章The Fallacy Of ReUse以及其他关于自治组件的文章。
因此,商店只是接收事件并更新其Atom中的命名空间状态的代码片段。

这将状态管理的复杂性转移到另一层。现在最难的是精确定义哪些是您的应用程序事件。


Note that this project is still very unstable and undocumented/not well tested. But we already use it here with great success. If you want to discuss about it or contribute, you can reach me on IRC: Sebastien-L in #reactjs.

使用这个框架开发单页应用的感觉。每次呈现时,启用调试模式,您可以看到:

  • 将JSON转换为虚拟DOM并将其应用于真实DOM所需的时间。
  • 记录状态以帮助您调试应用程序。
  • 通过React.addons.Perf浪费的时间。
  • 与先前状态相比的路径差异,以轻松了解已更改的内容。

请查看此屏幕截图:

enter image description here

这种框架可以带来一些优势,我还没有深入探讨过:
  • 您真的内置了撤销/重做功能(这在我的实际生产应用程序中可以直接使用,而不仅仅是一个TodoMVC)。然而,在许多应用程序中,大多数操作实际上会对服务器产生副作用,因此将UI恢复到先前状态并不总是有意义的,因为先前状态可能已过时。

  • 您可以记录状态快照,并在另一个浏览器中加载它们。CircleCI已在this video中展示了这一点。

  • 您可以以JSON格式记录用户会话的“视频”,将其发送到后端服务器进行调试或回放视频。您可以将用户会话实时流式传输到另一个浏览器以帮助用户(或间谍检查用户的实时UX行为)。发送状态可能会非常昂贵,但是像Avro这样的格式可能会有所帮助。或者,如果您的应用程序事件流是可序列化的,您可以简单地流式传输这些事件。我已经在框架中轻松实现了它,并且在我的生产应用程序中运行良好(仅供娱乐,尚未向后端传输任何内容)

  • 可以像ELM一样实现时间旅行调试

我制作了一个记录用户会话为JSON格式的功能的视频,供有兴趣的人观看。


很棒的写作!关于调试的最后一部分看起来很厉害 :) 你有使用Atom-React的示例应用程序吗? - Cotten
没有,但我计划实现一个TodoMVC版本作为基础文档(然而,我认为todomvc太简单了,因为它实际上没有处理ajax请求和网络延迟)。我会尽快添加一些文档。 - Sebastien Lorber
这看起来非常不错。再添加一些文档,它的发展潜力不可限量。 - Jacob Oscarson
当你写CQRS时,你可能想表达事件溯源。 - AlexG

3
你可以使用纯Flux而不需要另一个React包装器,以实现类似于Om应用程序状态 - 在此处检查它:https://github.com/steida/este 这是我非常完整的React入门工具包。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接