我在 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/交易!但他们需要一个光标,我在菜单项 View 中唯一的光标是当前菜单项,而不是完整的应用程序状态。所以我无法访问:位置。
这是如何处理的?
如果可能的话,我宁愿暂时避免 core.async 和 channels。
最佳答案
现在我们有了 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"))})
这只是一个想法 - 我还没有真正测试过它。
关于clojurescript - Om 应用程序状态和应用程序结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26354662/