4

次のようなコンポーネントとサブコンポーネントを使用して、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 とチャネルを避けたいと思います。

4

2 に答える 2

6

参照カーソルができたので、おそらく次のようなことができます。

(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"))})

これは単なるアイデアであり、実際にテストしたことはありません。

于 2014-10-21T17:05:37.417 に答える
2

はい、すべての更新は om/transact を通じて行う必要があります。または om/update!.

:init-state または :state でメイン カーソルをコントロールの状態に渡すことができます。これにより、更新のためにアクセスできるようになります。

または、om/build-all の使用を避け、ビルドを直接使用して、ここで指定されているように複数のカーソルをコントロールに渡すこともできます。

代わりに次のように呼び出します。

(map #(om/build menu-item-view {:main-cursor app :menu-cursor %}) (:menuitems app)) 
于 2014-10-15T11:47:09.500 に答える