Om应用程序状态和应用程序结构

时间:2014-10-14 07:10:12

标签: clojurescript om

我在Om中使用如下组件和子组件显示菜单:

(def app-state (atom {:location ""
                      :menuitems [["Pages" "/pages/"]
                                  ["Images" "/images/"]]}))

(defn menu-item-view [parent-cursor item owner]
  (reify
    om/IRender
    (render [this]
      (dom/li #js {:className (if (= (:location @app-state) (last item)) "active" "inactive")} 
        (dom/a #js 
               {:onClick (fn [_] (swap! app-state assoc :location (last @item)))} 
               (first item))))))

(defn menu-view [app owner]
  (reify
    om/IRender
    (render [this]
      (dom/li #js {:className "has-dropdown not-click"}
        (dom/a nil "Menu")
        (apply dom/ul #js {:className "dropdown"}
          (om/build-all (partial menu-item-view app) 
                        (:menuitems app)))))))

(om/root menu-view app-state
  {:target (. js/document (getElementById "menu"))})

我的问题是如何更新(@ app-state:location)并正确地重新呈现菜单?

上述代码中的更新:

(swap! app-state assoc :location (last @item))

确实有效,但树的更新不正确。

我怀疑我需要使用om / update!或者om / transact!但它们采用光标,我在菜单项视图中唯一的光标是当前菜单项,而不是完整的应用程序状态。所以我无法访问:location。

这是如何处理的?

如果可能的话,我宁愿暂时使用core.async和渠道。

2 个答案:

答案 0 :(得分:6)

既然我们有reference cursors你可能会做这样的事情:

(def app-state (atom {:location ""
                      :menuitems [["Pages" "/pages/"]
                                  ["Images" "/images/"]]}))

(defn location []
  (om/ref-cursor (:location (om/root-cursor app-state))))

(defn menu-item-view [item owner]
  (reify
    om/IRender
    (render [this]
      (let [x (location)]
        (dom/li #js {:className (if (= x (last item)) "active" "inactive")}
                (dom/a #js
                       {:onClick (fn [_] (om/update! x (last @item)))}
                       (first item)))))))

(defn menu-view [app owner]
  (reify
    om/IRender
    (render [this]
      (dom/li #js {:className "has-dropdown not-click"}
              (dom/a nil "Menu")
              (apply dom/ul #js {:className "dropdown"}
                     (om/build-all menu-item-view (:menuitems app)))))))

(om/root menu-view app-state
  {:target (. js/document (getElementById "menu"))})

这只是一个想法 - 我实际上没有测试过它。

答案 1 :(得分:2)

是的,所有更新都应该通过om / transact进行!或om / update!。

您可以将主光标传递到控件状态:init-state或:state。这样您就可以访问它进行更新。

或者,您可以避免使用om / build-all并直接使用build将多个游标传递给指定here的控件。

只需拨打以下电话:

(map #(om/build menu-item-view {:main-cursor app :menu-cursor %}) (:menuitems app))