1

在下面的代码中,我调度了两个点击事件:

;; 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]但这给出了同样的错误。一般来说,如何正确调度两个事件?

4

1 回答 1

0

这是对的:

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

这是正确的:

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

在此示例中,您将使用 3 个参数调度一个事件:

  • :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 Middlewares。在您的情况下,中间件将允许您对处理程序返回的值采取行动,如果它不符合您的期望,则可能会拒绝它。
于 2020-03-06T10:24:10.983 回答