Om 但在 javascript 中

Posted

技术标签:

【中文标题】Om 但在 javascript 中【英文标题】:Om but in javascript 【发布时间】:2014-11-05 14:44:41 【问题描述】:

我要成为 David Nolen 的 Om library 的粉丝了。

我想在我们的团队中构建一个不太大的网络应用程序,但我无法真正说服我的队友改用 ClojureScript。

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

我在想这样的事情:

    immutable-js 或 mori 用于不可变数据结构 js-csp 用于 CSP 只是应用状态原子的普通 javascript 对象 immutable-js 用于光标 用于跟踪应用程序状态并基于光标发送通知的东西

我在上面的第 5 个问题上苦苦挣扎。

有没有人涉足这个领域或有什么建议?也许有人尝试过使用 immutable-js 构建 react.js 应用?

【问题讨论】:

【参考方案1】:

2015 年 7 月编辑:目前最有前途的基于不变性的框架是 Redux!看一看!它不使用像 Om 这样的游标(Om Next 也不使用游标)。

游标并不是真正可扩展的,尽管使用了下面描述的 CQRS 原则,它仍然会在组件中创建太多样板,难以维护,并且当您想在现有应用程序中移动组件时会增加摩擦。

此外,许多开发人员不清楚何时使用和不使用游标,我看到开发人员在不应该使用的地方使用游标,这使得组件的可重用性不如采用简单道具的组件。

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

我写过关于不使用connect()here的缺点

尽管不再使用游标,但我的大部分答案仍然有效,恕我直言


我自己在我们的启动内部框架中完成了它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)/>

它有pure render, optimized out of the box的概念,就像在Om中一样


与 Om 的区别:

没有本地状态(this.setState(o) 禁止)

在 Atom-React 组件中,您不能拥有本地组件状态。 所有状态都存储在 React 之外。除非您有现有 Js 库的集成需求(您仍然可以使用常规的 React 类),否则您将所有状态存储在 Atom 中(即使是异步/加载值),并且整个应用程序会从主 React 组件重新呈现自身。 React 只是一个模板引擎,非常高效,可以将 JSON 状态转换为 DOM。我觉得这很方便,因为我可以在每次渲染时记录当前的 Atom 状态,然后调试渲染代码非常容易。感谢开箱即用的shouldComponentUpdate,它足够快,我什至可以在用户在文本输入上按下新键盘键或用鼠标悬停按钮时重新呈现整个应用程序。即使在手机上!

管理状态的独到方式(受 CQRS/EventSourcing 和 Flux 启发)

Atom-React 有一种非常自以为是的方式来管理受 FluxCQRS 启发的状态。一旦你拥有了 React 之外的所有状态,并且你有一种将 JSON 状态转换为 DOM 的有效方法,你会发现剩下的困难是管理你的 JSON 状态。

遇到的一些困难是:

    如何处理异步值 如何处理需要更改 DOM 的视觉效果(例如鼠标悬停或焦点) 如何组织您的状态以便在大型团队中扩展 Where to fire the ajax requests.

所以我最终提出了 Store 的概念,灵感来自 Facebook Flux architecture。 关键是我真的不喜欢 Flux 存储实际上可以依赖另一个存储,需要通过复杂的调度程序来编排操作。您最终必须了解多个商店的状态才能呈现它们。

在 Atom-React 中,Store 只是 Atom 持有的状态中的“保留命名空间”。

所以我更喜欢从应用程序中发生的事件流中更新所有商店。每个 store 都是独立的,不访问其他 store 的数据(就像在 CQRS 架构中一样,组件接收完全相同的事件,托管在不同的机器上,并按照自己的意愿管理自己的状态)。这使得维护变得更容易,因为当您开发一个新组件时,您只需要了解一个商店的状态。这会导致数据重复,因为在某些情况下,现在多个商店可能必须保留相同的数据(例如,在 SPA 上,您可能希望在应用程序的许多地方都使用当前用户 ID)。但是,如果 2 个商店将同一个对象置于其状态(来自一个事件),这实际上不会消耗任何额外的数据,因为这仍然是 1 个对象,在 2 个不同的商店中被引用了两次。

要了解这种选择背后的原因,您可以阅读 CQRS 负责人 Udi Dahan、The Fallacy Of ReUse 和其他人关于自治组件的博客文章。

因此,存储只是一段代码,用于接收事件并在 Atom 中更新其命名空间状态。

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


请注意,该项目仍然非常不稳定且未记录/未经过良好测试。但是我们已经在这里使用它并取得了巨大的成功。如果你想讨论或贡献,你可以通过 IRC 联系我:Sebastien-L#reactjs

这就是用这个框架开发 SPA 的感觉。每次渲染时,使用调试模式,您都有:

将 JSON 转换为虚拟 DOM 并将其应用于真实 DOM 所花费的时间。 记录的状态可帮助您调试应用 感谢React.addons.Perf浪费时间 与之前状态相比的路径差异,可轻松了解发生了什么变化

查看此屏幕截图:

这种框架可以带来的一些我还没有探索过的优点:

您确实内置了撤消/重做(这在我的实际生产应用程序中开箱即用,而不仅仅是 TodoMVC)。但是恕我直言,许多应用程序中的大多数操作实际上都会在服务器上产生副作用,因此将 UI 反转到以前的状态并不总是有意义,因为以前的状态会过时

您可以记录状态快照,并将它们加载到另一个浏览器中。 CircleCI 在this video

上展示了这一点

您可以以 JSON 格式录制用户会话的“视频”,将它们发送到您的后端服务器进行调试或重播视频。您可以将用户会话实时流式传输到另一个浏览器以获得用户帮助(或监视以检查用户的实时 UX 行为)。发送状态可能非常昂贵,但可能像 Avro 这样的格式可以提供帮助。或者,如果您的应用事件流是可序列化的,您可以简单地流式传输这些事件。我已经在框架中轻松实现了它,它可以在我的生产应用程序中运行(只是为了好玩,它还没有向后端传输任何东西)

可以像在 ELM 中那样进行时间旅行调试

我已经为感兴趣的人制作了a video of the "record user session in JSON" feature。

【讨论】:

写得好!关于调试的最后一部分看起来很天才:) 你有任何使用 atom-react 的示例应用程序吗? 不,但我计划实现一个 TodoMVC 版本作为基础文档(但是我认为 todomvc 太简单了,因为它实际上不处理 ajax 请求和网络延迟)。我会尽快添加一些文档 这看起来真不错。添加更多文档,不知道它会走多远。 您在编写 CQRS 时可能指的是事件溯源【参考方案2】:

您可以在没有另一个 React 包装器和纯 Flux 的情况下拥有类似 Om 的应用程序状态 - 在这里查看 https://github.com/steida/este 这是我非常完整的 React 入门工具包。

【讨论】:

以上是关于Om 但在 javascript 中的主要内容,如果未能解决你的问题,请参考以下文章

Firefox 中缓慢的 CSS3 动画闪烁

所有Ember组件实例共享变量的最佳方法是什么?

JavaScript语法

JavaScript语句

JavaScript - 对象

jquery ajax使用JSONP解决跨域问题