ClojureScript / OM:从另一个组件更新组件的状态 - 或者:使用全局状态

ClojureScript / OM: update a component's state from another component - or: working with global state

我正在通过一个非常简单的应用程序开始使用 om 和 ClojureScript。

我的全局应用程序状态如下所示:

(def app-state (atom {:animals [ {:name "dog" :img "pic01.jpg"}
                                 {:name "cat" :img "pic02.jpg"}
                                 {:name "mouse" :img "pic03.jpg"}
                                 {:name "camel" :img "pic04.jpg"}]}))

向量 "animals" 中每个散列映射的名称 属性 由 om 呈现为 HTML 列表结构(i.g.LI-tag)我称之为 "menu" 的组件。每个条目都由另一个名为 "entry" 的组件呈现。 (i.g。作为 UL 元素)。 每当用户悬停列表条目之一时,条目的外观就会发生变化(可能背景会发生变化)。我在入口组件中捕获这些当前状态,我通过 om/IInitState.

对其进行初始化

到目前为止这有效。现在我想添加另一个组件,称为 "display"。每当用户单击列表中的条目时,它应该能够显示与全局状态中的动物名称相关联的图像。我在问自己解决这个问题的最佳方法是什么。

我看到两种可能性:

在 "display" 组件中保持本地状态,该状态由 "entry" 组件的 onClick 事件更新。 在这里,我的问题是:如何从另一个组件更新组件的状态?

或者在全局状态中引入另一个属性,可能叫:"active_section",由入口组件中的onClick事件更新,由"display"组件读取。但这有必要吗?

不确定我是否 100% 理解您的要求,但我愿意付出 2 美分的代价。

一般来说,我会避免涉及一个组件以某种方式更新另一个组件中的本地状态的设计。这会在组件之间创建紧密耦合,这可能不是您真正想要的。最好 design/develop 您的组件,这样他们对其他组件的了解就很少(如果有的话)。

基于 React 的应用程序的最佳方法是将您的状态保持在全局状态原子中。在这种情况下,我会让一个组件(菜单组件?)在全局状态中设置一个 :visible 或 :current 属性 值,指示当前动物。您的其他组件将根据 属性 设置为 true 的条目渲染动物。

这样做的另一个好处是,如果您决定添加需要在当前 'animal' 上运行的其他组件,它也可以使用该信息。

将所有可能触发 DOM 渲染的状态变化保存在一个地方也可以使调试更容易。此外,请查看 om-next(有一个 quick start 教程),因为它有一个针对 setting/geetting 状态的新方法,它有望使事情比旧的 'cursor' 方法简单得多.

我使用两种不同的方法。第一个是有一个组件 "broadcast" 它的状态是一条消息。例如,我有一个日历组件 "broadcasts" 它是 "current date"。当有人点击不同的日期时,它会广播该新日期。任何组件都可以侦听该消息并根据需要进行自我更新。

我的第二种方法是让组件广播消息 "to another" 组件。它通过广播另一个组件正在侦听的 "type" 消息来做到这一点。例如,我有一个要编辑客户的组件。它将要编辑的 "customer" 广播到 "Customer Edit Component"。 "Customer Edit Component" 决定是否可以显示客户并处理编辑。如果它决定保存更改,则广播 "save" 消息。 "save" 消息列表处理请求并广播 "save" 的结果。显示客户信息的组件处理 "updated" 客户消息并显示更改。

唯一的耦合是在消息总线和消息之间。所有这些都是使用 core.async.

实现的

你应该预先决定的问题是是否有多个总线(通道)。另一个问题是组件需要 short-circuit 未定向到它们的消息。

我有一个特殊组件可以侦听所有消息以进行调试。

我会小心地将所有全局数据直接绑定到组件。我更愿意将全局数据视为数据库,而不是组件的内部数据。