Перекадровка: добавление нового элемента карты во вложенный вектор
У меня есть эта структура (упорядоченная карта) в моей "БД" с ключевым словом ":questions":
{:33 {:question "one", :id 33, :answers [{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}]}},
{:39 {:question "two", :id 39, :answers []}},
{:41 {:question "three", :id 41, :answers [{:id 29, :question_id 41, :answer "one", :correct false}
{:id 35, :question_id 41, :answer "two", :correct true}]}}
Я могу добавить новый вопрос в обработчик событий "re-frame/reg-event-db", добавив:
(assoc-in db [:questions (:id response)] new-map-stuff)
но я не знаю, как добавить карту в ключ ": ответы". Кроме того, я боюсь, что я задаю все вопросы каждый раз, когда добавляю новый ответ.
Я читал о перехватчике "путь" (вид "обновления"), но я не могу найти пример, как его использовать.
1 ответ
Вы делаете это так же, как в простом замыкании, используя update-in
, Первый старт в Clojure CheatSheet:
http://jafingerhut.github.io/cheatsheet/clojuredocs/cheatsheet-tiptip-cdocs-summary.html
или версия ClojureScript: http://cljs.info/
Посмотрите на документы для update-in
: https://clojuredocs.org/clojure.core/update-in
Вам нужно 2 компонента
- Путь для навигации по сайту мутации
- Функция для выполнения мутации с учетом точки из (1).
Вы не указали свои данные полностью. Я предполагаю, что это выглядит так:
(def db {:questions [
{:33 {:question "one", :id 33,
:answers [{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}]}},
{:39 {:question "two", :id 39, :answers []}},
{:41 {:question "three", :id 41,
:answers [{:id 29, :question_id 41, :answer "one", :correct false}
{:id 35, :question_id 41, :answer "two", :correct true}]}}]})
Я сделаю новый answer
карту добавить:
(def new-answer {:id 42, :question_id 442, :answer "The Ultimate", :correct false})
Этот код показывает процесс по частям.
(let [submap (get-in db [:questions 0 :33 :answers])
modified (conj submap new-answer)
final-answer (update-in db [:questions 0 :33 :answers] conj new-answer) ]
Сначала навигация, чтобы получить submap
:
submap =>
[{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}]
И как вы добавите новый ответ:
modified =>
[{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}
{:id 42, :question_id 442, :answer "The Ultimate", :correct false}]
И собрать все это в одну операцию:
final-answer =>
{:questions
[{:33
{:question "one",
:id 33,
:answers
[{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}
{:id 42, :question_id 442, :answer "The Ultimate", :correct false}]}}
{:39 {:question "two", :id 39, :answers []}}
{:41
{:question "three",
:id 41,
:answers
[{:id 29, :question_id 41, :answer "one", :correct false}
{:id 35, :question_id 41, :answer "two", :correct true}]}}]}
Все это работает одинаково в ClojureScript, как и в Clojure.
Не беспокойтесь об использовании path
перехватчик. Я думаю, что это смущает вещи больше, чем помогает. И не беспокойтесь о скорости рендера, если:
- У вас это работает и проверено, и вы знаете, что это правильно.
- Вы измерили скорость рендеринга и можете задокументировать, что есть проблема и количество, которое необходимо ускорить.
- Для длинных списков вещей посмотрите на
key
метаданные, которые вы можете добавить к каждому элементу списка для реагента. Смотрите: Reagent React Clojurescript Предупреждение: Каждый элемент в seq должен иметь уникальный ключ:
Обновить
Обратите внимание, что submap
а также modified
показаны только в демонстрационных целях, чтобы показать, как update-in
работает. update-in
Выражение - это единственное, что вы бы включили в свой код. Также обратите внимание, что update-in
только использует db
а также new-answer
,