Почему db печатает #object[Object [object Object]] в рефрейминге?

В следующем коде я отправляю два события по клику:

;; event
(reg-event-db
 :some
 (fn [db [_ some-val]]
   (prn "The db is" db)
   (assoc db :some some-val)
   ))

;; another event
(reg-event-db
 :another
 (fn [db [_ another-val]]
   (prn "The db is" db)
   (assoc db :another another-val)
   ))

;; button
[:input {:type "button" :value "Button"
         :on-click #(do
                       (dispatch [:some :some-val])
                       (dispatch [:another :another-val]))}]

Но вместо того, чтобы печатать карту БД, он печатает "The db is" #object[Object [object Object]], а затем

Error: No protocol method IAssociative.-assoc defined for type object: [object Object]

Что я делаю не так? Я также пытался сделать #(dispatch [:some :some-val :another another-val], но это дало ту же ошибку. Вообще, как правильно отправить два события?


person zengod    schedule 03.03.2020    source источник


Ответы (1)


Это правильно:

(do
  (dispatch [:first-event :some-value])
  (dispatch [:second-event :other-value]))

Это не правильно:

(dispatch [:some :some-val :another another-val])

В этом примере вы отправляете одно событие с тремя аргументами:

  • :some — название события,
  • :some-val — первый аргумент,
  • :another — второй аргумент,
  • another-val — третий аргумент.

Ошибка, с которой вы сталкиваетесь, связана не с тем, как вы dispatch делаете события, а скорее с вашим db состоянием. Разберем пошагово:

Если (prn db) выводит #object[Object [object Object]], это означает, что db является объектом JavaScript.

Если (assoc db …) не работает с No protocol method IAssociative.-assoc defined for type object: [object Object], это означает, что значение db не поддерживает функцию assoc. Функция assoc определяется протоколом (например, интерфейсом), и этот протокол реализован на картах. Так вот, db это не карта.

Почему db должен быть объектом JavaScript, а не картой Clojure?

Когда вы используете (reg-event-db :event-name handler-function), значение, возвращаемое handler-function, заменит состояние db. Если по ошибке вы вернете объект JS, он станет новым значением db, и это новое неправильное значение db будет передано последующим обработчикам событий. Поэтому весьма вероятно, что один из ваших обработчиков событий возвращает объект JavaScript.

Как бы я решил эту ситуацию:

  • используйте (js/console.log db) вместо (prn db). Вы сможете увидеть, что находится внутри этого js-объекта. prn не знает, как правильно печатать js-объекты.
  • убедитесь, что cljs-devtools установлен и запущен. Это позволяет вам исследовать сложные объекты в консоли. В следующий раз, когда возникнет эта проблема, вы сразу увидите проблемное значение, а не непрозрачное строковое представление.
  • используйте reg-event-fx вместо reg-event-db. Хотя он немного более подробный, он сделает более понятным для человеческого глаза, какое значение вы вкладываете в db.
  • если вы хотите пойти дальше и убедиться, что это никогда не повторится, взгляните на Re-Frame Middleware. В вашем случае промежуточное ПО позволит вам воздействовать на возвращаемые обработчиками значения и потенциально отклонять их, если они не соответствуют вашим ожиданиям.
person Geoffrey Gaillard    schedule 06.03.2020