gpt4 book ai didi

clojurescript - om.next 其他组件状态的突变不会导致其他组件重新渲染

转载 作者:行者123 更新时间:2023-12-04 06:26:53 26 4
gpt4 key购买 nike

我正在更新我的一个突变中的状态,其中一部分未被该组件使用,但被另一个组件使用。当我执行 mutate 时,我看到应用程序状态在 repl 中更新,如果我由于其他原因导致组件重新渲染,它会正确显示,但我无法让 mutate 安排重新 -第二个组件的渲染。在下面的示例中,单击按钮应该会减少第二个列表中颜色名称附近的值,但事实并非如此。

有一些例子显示在 mutate 返回中使用 :value [k k],但是那些抛出错误,一定是过时的教程,因为当前格式是 :value {:keys [...]},所以说代码和一些教程。但是我找不到 om.next 的任何部分实际上使用 :keys 作为不是解构操作的关键字(所以不使用 :keys 作为实际关键字,但它是一个常用词所以我可能在某处错过了一个)

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

=> (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)
)

最佳答案

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

{:keys [click-cb-fn]} (om/get-computed this)

当您调用 om/transact! 时,重新渲染是从您作为第一个参数传递的组件向下完成的 - this。因此,将其发挥到极致,如果所有 om/transacts! 都是从根组件完成的,并且所有函数都通过计算 Prop 传递下来,那么您将永远不会遇到重新渲染问题。

但您不必向下传递函数。另一种方法是将它们保留在触发按钮所在的同一组件中,而不是向下传递(再次通过计算 Prop )父组件的 this。重要的是 om/transact! 的第一个参数是什么组件 - 从任何你喜欢的地方调用 om/transact!

后续读取是考虑重新渲染时要考虑的另一件事,但不是您给出的示例 - 当您需要重新渲染的组件位于渲染树的不同子分支中时,最好考虑它们,其中使用公共(public)根的 this 是不切实际的。

另一件需要注意的事情是,一个 mutate 的 value 是“仅用于文档”。所以无论你放在那里什么都没有效果。

关于clojurescript - om.next 其他组件状态的突变不会导致其他组件重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39320524/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com