首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >其他组件状态的om.next变异不会导致其他组件重新呈现。

其他组件状态的om.next变异不会导致其他组件重新呈现。
EN

Stack Overflow用户
提问于 2016-09-04 19:09:11
回答 1查看 233关注 0票数 3

我正在更新我的一个突变状态,其中一部分不是这个组件使用的,而是另一个组件使用的。当我进行变异时,我会在repl中看到app状态被更新,如果我由于其他原因导致组件重新呈现,它将显示正确,但是我不能让变体安排第二个组件的重呈现。在下面的示例中,单击一个按钮应该会减少第二个列表中颜色名称附近的值,但它不会。

有一些示例显示了使用:变量返回中的值k,但是那些抛出错误,必须是过时的教程,因为当前格式是:value {:key.},代码和一些教程是这样说的。然而,我找不到om.next的任何部分实际使用:key作为一个关键字而不是destructure操作(所以不使用:key作为一个实际的关键字,但它是一个常见的词,所以我可能在某个地方遗漏了一个关键字)

在repl中,我看到了这个应用程序状态:

代码语言:javascript
运行
复制
=> (om/app-state reconciler)
#object [cljs.core.Atom {:val 
  {:tiles [[:tile/by-pos "a7"]
           [:tile/by-pos "a9"]
           [:tile/by-pos "a11"]],
   :inventory [[:inv/by-color "red"]
               [:inv/by-color "blue"]
               [:inv/by-color "green"]],
   :tile/by-pos {"a7" {:pos "a7", :color nil},
                 "a9" {:pos "a9", :color nil},
                 "a11" {:pos "a11", :color nil}},
   :inv/by-color {"red" {:color "red", :remaining 2},
                  "blue" {:color "blue", :remaining 1},
                  "green" {:color "green", :remaining 1}}}}]

我遗漏了什么?

代码语言:javascript
运行
复制
(ns omnexttest.core
  (:require [goog.dom :as gdom]
            [om.next :as om :refer-macros [defui]]
            [om.dom :as dom]))

(defmulti read om/dispatch)

(defmethod read :default
    [{:keys [state] :as env} key params]
      (let [st @state ]
            (if-let [[_ value] (find st key)]
                    {:value value}
                    {:value :not-found})))

(defmethod read :tiles
    [{:keys [state] :as env} key params]
     {:value (into [] (map #(get-in @state %) (get @state key))) })

(defmethod read :inventory
    [{:keys [state] :as env} key params]
     {:value (into [] (map #(get-in @state %) (get @state key))) })

(defmulti mutate om/dispatch)

(defmethod mutate 'draw/edit-edge
  [{:keys [state] :as env} _ {:keys [this pos color]}]
    {:value {:keys [[:inv/by-color color :remaining]]}
     :action (fn []  (do
               (swap! state assoc-in [:tile/by-pos pos :color] color )
               (swap! state update-in [:inv/by-color color :remaining] dec)))})

(defn hex-color
  [ this pos color ]
    (om/transact! this `[(draw/edit-edge ~{:this this :pos pos :color color})]))

(defui TileView
    static om/Ident
    (ident [this {:keys [pos]}] [:tile/by-pos pos])
    static om/IQuery
    (query [this] '[:pos :color])
    Object
    (render [this]
      (let [{:keys [pos color] :as props} (om/props this)]
          (dom/li nil
            (str pos " " color)
            (for [color ["red" "green" "blue"]]
              (dom/button #js { :onClick (fn [e] (hex-color this pos color)) }
                       color))))))

(def tile-view (om/factory TileView {:keyfn :pos}))

(defui InvView
    static om/Ident
    (ident [this {:keys [color]}] [:inv/by-color color])
    static om/IQuery
    (query [this] '[:color :remaining])
    Object
    (render [this]
      (let [{:keys [color remaining] :as props} (om/props this) ]
        (dom/li nil (str color " " remaining)))))

(def inv-view (om/factory InvView {:keyfn :color}))

(def app-state {
                      :tiles [{ :pos "a7"  :color nil }
                              { :pos "a9"  :color nil }
                              { :pos "a11" :color nil }
                              ]
                      :inventory [{ :color "red" :remaining 2}
                                  { :color "blue" :remaining 1}
                                  { :color "green" :remaining 1}]
                      })

(defui MapView
       static om/IQuery
       (query [this]
              [{:tiles (om/get-query TileView)}
               {:inventory (om/get-query InvView) }])
       Object
       (render [this]
               (let [tiles (-> this om/props :tiles)
                     inv (-> this om/props :inventory) ]
                (dom/div nil
                  (dom/ul nil
                   (mapv tile-view tiles))
                  (dom/ul nil
                   (mapv inv-view inv))))))

(def reconciler
  (om/reconciler
    {:state app-state
     :parser (om/parser {:read read :mutate mutate})}))

(om/add-root! reconciler
  MapView (gdom/getElement "map"))

(defn on-js-reload []
  ;; optionally touch your app-state to force rerendering depending on
  ;; your application
  ;; (swap! app-state update-in [:__figwheel_counter] inc)
)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-09 14:07:53

传递给om/transact!om/transact!对于重呈现非常重要,因此在这里,如果this用于MapView组件,那么所有三个组件都将被重新呈现。您可以在MapView中使用这个函数(因此使用MapView's this),但是可以从TileView调用它。在TileView's render中,您需要这样的东西:

代码语言:javascript
运行
复制
{:keys [click-cb-fn]} (om/get-computed this)

当您调用om/transact!时,重呈现将从作为第一个参数- this传递的组件中执行。因此,如果所有的om/transacts!都是从根组件完成的,并且所有函数都是通过计算道具传递下来的,那么要做到这一点,就永远不会出现重新呈现问题。

但你不必把函数传递下去。另一种方法是将它们保存在触发按钮所在的同一个组件上,然后传递给父组件的this (同样是通过计算道具传递)。重要的是,om/transact!的第一个参数是什么组件--从任何您喜欢的地方调用om/transact!

在考虑重呈现时,需要考虑的另一件事是读,但对于您给出的示例,最好考虑的是当需要重新呈现的组件位于呈现树的另一个子分支中时,在那里使用公共根的this是不实际的。

另一件需要注意的是,变异的value“只是用于文档”。所以不管你在那里放什么都不会有效果。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39320524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档