Как обновить вектор реагента в атоме
У меня есть атом Реагента:
(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
вектор. Когда я разыграю order
Я только что получил последнее значение.
Как правильно добавить (и удалить) значения в мой :toppings
вектор?
3 ответа
Вы можете обновить начинки с:
(swap! order update :toppings conj "Pepperoni")
Просто чтобы объяснить немного больше, когда вы делаете (swap! (:toppings order) ...)
, вы получаете :toppings
ключ от order
что бы иметь смысл, если бы это была карта, но это атом, так (:toppings order)
возвращается nil
,
Первый аргумент swap!
всегда должен быть атом (Reagent
атомы работают так же). Второй аргумент должен быть функцией, которая принимает содержимое атома в качестве первого аргумента. Затем вы можете указать дополнительные аргументы, которые будут переданы в аргумент функции.
Вместо ответа 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")))
Сейчас update
имеет ту же подпись, что и fn 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.
Я бы включил 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")