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