5

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

(定义小节视图 [小节所有者]
  (具体化
     om/IInitState
     (初始化状态 [this]
        {:collapsed true}))

问题是每个小节的视图状态可以通过collapse-expand-all 按钮或为每个小节显示的单独按钮以两种方式影响。

为了处理 expand-compress-all 有一个全局折叠状态保存在表单本地状态中:

(defn form-view [数据所有者]
  (具体化
    om/IInitState
    (初始化状态 [this]
       {:all-collapsed true})))

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

(om/update-state!所有者:未折叠)

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

或者在哪里是保存崩溃状态的正确位置(本地状态或应用程序状态),该状态可能受到组件树不同级别的不同触发器的影响?

4

2 回答 2

2

我是 core.async 的粉丝,我会使用通道来实现它。我会让 Sections 监听 Co​​llapse/Expand 消息,并在它到来时更改本地状态。本地状态更改将导致重新绘制。扩展单个部分只会更新该部分的本地状态。

于 2015-02-26T21:41:35.633 回答
2

如果您正在考虑时间和因果关系以“显示正确的视图”,那么您就错过了 React/Om 的观点。你不应该做出那个决定。您应该只将显示链接到一个状态,并确保该状态是正确的。正如混沌规则所说,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")))))

万一我错过了什么,完整的例子在这里。看起来很多,但根据我的经验,这是实现良好的关注点分离的最佳方式。教程中有另一个类似的例子。

于 2015-02-27T11:07:04.177 回答