Clojurescript Om:处理不同组件中的本地状态变化

时间:2015-02-26 15:44:11

标签: clojurescript om

我正在构建一个基于om的表单,可以查看子部分是折叠还是展开。 视图状态保存在子部分本地状态:

(defn subsection-view [subsection owner]
  (reify
     om/IInitState
     (init-state [this]
        {:collapsed true}))

问题是每个子部分视图状态可以通过折叠 - 展开 - 全部按钮或为每个子部分显示的单独按钮双向实现。

为了处理expand-compress-all,全局崩溃状态以本地状态保存:

(defn form-view [data owner]
  (reify
    om/IInitState
    (init-state [this]
       {:all-collapsed true})))

显然,通过更新本地状态下的折叠状态来处理两个按钮on-click事件。

(om/update-state! owner :collapsed not)

我的问题是我应该如何知道哪个状态最后更新才能显示正确的视图?

正确的位置(本地状态或应用程序状态)在哪里保存可能从组件树的不同级别中的不同触发器生效的崩溃状态?

2 个答案:

答案 0 :(得分:2)

我是core.async的粉丝,我会使用频道实现它。我会让章节听取崩溃/展开消息,当它改变当地状态时。当地的州改变将导致重新抽签。扩展单个部分仅更新该部分的本地状态。

答案 1 :(得分:2)

如果您正在考虑时间和因果关系以“显示正确的视图”,那么您将缺少React / Om的观点。你不应该做出这个决定。您应该将显示器链接到一个状态,并确保该状态是正确的。正如Chaos Rules所说,core.async是要走的路。

由于字段组件已经耦合到外部的东西(全部折叠按钮),我只会在窗体的本地状态内建模collapsed /然后我会为字段提供一个collapse-ch通道,以便他们点击时可以回复。最后,我会在IWillMount中设置一个事件处理程序来监听这些点击:

(def init-state [true true true])

(defn form-view [data owner]
  (reify
    om/IInitState
    (init-state [_]
      {:collapsed init-state 
       :collapse-ch (chan)})
    om/IWillMount
    (will-mount [_]
      (let [collapse-ch (om/get-state owner :collapse-ch)]
        (go (loop []
              (let [index (<! collapse-ch)]
                (om/update-state! owner [:collapsed index] not))
              (recur)))))
    om/IRenderState
    (render-state [_ {:keys [collapsed collapse-ch]}]
      (dom/div nil
               (dom/button
                #js {:onClick (fn [_]
                                (om/set-state! owner :collapsed init-state))}
                "Collapse All")
               (apply dom/div nil
                      (map #(om/build field-view {:collapsed? %1}
                                      {:init-state {:index %2
                                                    :collapse-ch collapse-ch}})
                           collapsed
                           (range)))))))

至于字段,他们只需要在点击频道时将其索引放在频道上:

(defn field-view [data owner]
  (reify
    om/IRenderState
    (render-state [_ {:keys [index collapse-ch]}]
      (dom/button #js {:onClick (fn [_]
                                  (go (>! collapse-ch index)))}
                  (if (:collapsed? data)
                    "Collapsed"
                    "Showing")))))

如果我错过了某些内容,则完整示例为here。它看起来很多,但根据我的经验,它是实现关注点合理分离的最佳方式。 tutorial中还有另一个类似的例子。