如何更新原子中的试剂矢量

时间:2017-09-27 18:28:33

标签: clojure clojurescript reagent

我有一个Reagent原子:

(defonce order (r/atom {:firstName "" :lastName "" :toppings [] }))

我想在:toppings向量中添加浇头。我尝试了很多变化:

(swap! (:toppings order) conj "Pepperoni")给了我:Uncaught Error: No protocol method ISwap.-swap! defined for type null:

(swap! order :toppings "Pepperoni")有点工作,但只是更新顺序,而不是:toppings向量。当我deref order时,我得到了最新的价值。

:toppings向量添加(和删除)值的正确方法是什么?

3 个答案:

答案 0 :(得分:5)

只是为了解释一下,当你(swap! (:toppings order) ...)时,你正在从:toppings检索order密钥,如果它是一张地图就会有意义,但它是&#39} ; s是一个原子,所以(:toppings order)返回nil

swap!的第一个参数应始终为原子(Reagent原子以相同的方式工作)。第二个参数应该是一个以atom的内容为第一个参数的函数。然后,您可以选择提供更多将传递给函数参数的参数。

您可以执行以下操作,而不是minhtuannguyen的答案:

(swap! order
  (fn a [m]
    (update m :toppings
      (fn b [t]
        (conj t "Pepperoni")))))

fn a接收原子内的地图,将其绑定到m,然后更新它并返回一个新的地图,它将成为原子的新值。

如果您愿意,可以重新定义fn a以获取第二个参数:

(swap! order
  (fn a [m the-key]
    (update m the-key
      (fn b [t]
        (conj t "Pepperoni"))))
  :toppings)

:toppings现在作为fn a的第二个参数传递,然后传递到update内的fn a。我们可以对update的第三个参数执行相同的操作:

(swap! order
  (fn a [m the-key the-fn]
    (update m the-key the-fn))
  :toppings
  (fn b [t]
    (conj t "Pepperoni")))

现在updatefn a具有相同的签名,因此我们根本不再需要fn a。我们可以直接代替update

提供fn a
(swap! order update :toppings
  (fn b [t]
    (conj t "Pepperoni")))

但我们可以坚持下去,因为update也接受更多的参数,然后传递给提供给它的函数。我们可以重写fn b以获取另一个论点:

(swap! order update :toppings
  (fn b [t the-topping]
    (conj t the-topping))
  "Pepperoni"))

conj再次与fn b具有相同的签名,因此fn b是多余的,我们可以在其位置使用conj

(swap! order update :toppings conj "Pepperoni")

因此,我们最终得到了minhtuannguyen的答案。

答案 1 :(得分:4)

您可以使用以下命令更新配料:

(swap! order update :toppings conj "Pepperoni")

答案 2 :(得分:4)

我会将toppings变成一个集合。我不认为你想在集合中重复浇头,所以一套是合适的:

(defonce order (r/atom {:first-name "" :last-name "" :toppings #{}})) ; #{} instead of []

然后您仍然可以conj,如另一个答案中所述:

(swap! order update :toppings conj "Pepperoni")

但你也可以disj

(swap! order update :toppings disj "Pepperoni")