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

jma*_*svt 2 clojure clojurescript reagent

我有一个Reagent原子:

(defonce order (r/atom {:firstName "" :lastName "" :toppings [] }))
Run Code Online (Sandbox Code Playgroud)

我想在: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向量添加(和删除)值的正确方法是什么?

Erw*_*ers 5

我会toppings变成一个集合。我认为您不希望集合中出现重复的浇头,因此一套是合适的:

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

然后你仍然可以conj按照另一个答案中的说明:

(swap! order update :toppings conj "Pepperoni")
Run Code Online (Sandbox Code Playgroud)

但你也可以disj:

(swap! order update :toppings disj "Pepperoni")
Run Code Online (Sandbox Code Playgroud)


gra*_*ero 5

只是为了解释一下,当你这样做时(swap! (:toppings order) ...),你正在检索:toppings密钥order,如果它是一个地图就有意义,但它是一个原子,所以(:toppings order)返回nil.

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

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

(swap! order
  (fn a [m]
    (update m :toppings
      (fn b [t]
        (conj t "Pepperoni")))))
Run Code Online (Sandbox Code Playgroud)

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

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

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

: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")))
Run Code Online (Sandbox Code Playgroud)

现在update有相同的签名fn a,所以我们根本不再需要fn a.我们可以直接提供update以下代码fn a:

(swap! order update :toppings
  (fn b [t]
    (conj t "Pepperoni")))
Run Code Online (Sandbox Code Playgroud)

但是我们可以继续前进,因为update它还接受更多的参数,然后传递给提供给它的函数.我们可以重写fn b另一个论点:

(swap! order update :toppings
  (fn b [t the-topping]
    (conj t the-topping))
  "Pepperoni"))
Run Code Online (Sandbox Code Playgroud)

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

(swap! order update :toppings conj "Pepperoni")
Run Code Online (Sandbox Code Playgroud)

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