我正在更新我的一个突变中的状态,并且该部分没有使用它的一部分,而是另一部分。当我执行mutate时,我看到app-state在repl中更新,如果我因为其他原因导致组件重新渲染,它将正确显示,但是我无法通过mutate来调度re-渲染第二个组件。在下面的示例中,单击按钮应该减少第二个列表中颜色名称附近的值,但它不会。
有一些示例显示在mutate返回中使用:value [kk],但那些抛出错误,必须是过时的教程,因为当前格式为:value {:keys [...]},所以说代码和一些教程。但是,我无法找到om.next的任何部分实际使用:键作为关键字,不是结构操作(因此不使用:键作为实际关键字,但它是一个常用词,所以我可能有错过了一个地方)
在repl中我看到这个app-state:
=> (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}}}}]
我错过了什么?
(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)
)
答案 0 :(得分:3)
传递到this
的{{1}}对于重新呈现非常重要,因此如果om/transact!
用于this
组件,则所有三个组件都将重新呈现渲染。您可以在MapView
中使用该功能(因此使用MapView
MapView's
),但可以从this
调用该功能。在TileView
TileView's
中你需要这样的东西:
render
当您致电{:keys [click-cb-fn]} (om/get-computed this)
时,您从作为第一个参数传递的组件向下完成重新渲染 - om/transact!
。因此,为了将其发挥到极致,如果所有this
都是从根组件完成的,并且所有函数都通过计算道具向下传递,那么您将永远不会重新渲染问题。
但是你不必通过功能。另一种方法是将它们保持在触发按钮所在的同一组件上,而是向下传递(再次通过计算出的道具)父组件om/transacts!
。重要的是this
的第一个参数是什么组件 - 从你喜欢的地方调用om/transact!
。
在考虑重新渲染时,跟随读取是另一件需要考虑的事情,但不是您给出的示例 - 当需要重新渲染的组件位于渲染树的不同子分支中时,最好考虑它们,使用共同的根om/transact!
是不切实际的。
另一件值得注意的事情是变异的this
只是用于文档'。所以无论你放在哪里都没有效果。