在Clojure re frame中如何处理AJAX成功/错误响应?
我喜欢re-frame,但我意识到我在寻找处理AJAX响应的好模式时遇到了一些困难 我的情况如下: 我有一个“全局”事件处理程序,它会触发一些AJAX调用并分派给其他全局事件处理程序,具体取决于该调用是否成功,例如:在Clojure re frame中如何处理AJAX成功/错误响应?,clojure,re-frame,Clojure,Re Frame,我喜欢re-frame,但我意识到我在寻找处理AJAX响应的好模式时遇到了一些困难 我的情况如下: 我有一个“全局”事件处理程序,它会触发一些AJAX调用并分派给其他全局事件处理程序,具体取决于该调用是否成功,例如: (reg-event-db :store-value (fn [db [_ value]] (do-ajax-store value :on-success #(dispatch [:store-value-success %])
(reg-event-db :store-value
(fn [db [_ value]]
(do-ajax-store value
:on-success #(dispatch [:store-value-success %])
:on-error #(dispatch [:store-value-error %])
db))
(reg-event-db :store-value-success
(fn [db [_ result]]
(assoc db :foobar result)))
(reg-event-db :store-value-error
(fn [db [_ error]]
(assoc db :foobar nil
:last-error error)))
(我知道reg event fx
等等,为了简洁起见,我在这里避免使用它,因为我认为这对我的问题没有任何影响)
我还有(多个不同的)UI组件,它们可能触发:store value
事件,如下所示:
(defn button []
(let [processing? (reagent/atom false)]
(fn button-render []
[:button {:class (when @processing? "processing")
:on-click (fn []
(reset! processing? true)
(dispatch [:store-value 123]))}])))
因此,在本例中,组件具有本地状态(处理?
),这应该取决于AJAX调用是否仍在进行中
现在,为了在AJAX调用完成后将处理重置为标志,让按钮
组件对事件:store value success
和:store value error
作出反应的正确模式是什么
目前,我正在通过传递回调来解决这个问题,但这看起来真的很糟糕,因为它让事件处理程序的代码中充斥着不属于那里的东西
我想到的最好的解决方案是让按钮
组件能够钩住:store value success
和:store value error
事件,并为这些事件安装自己的处理程序,如下所示:
(defn button []
(let [processing? (reagent/atom false)]
(reg-event-db :store-value-success
(fn [db _]
(reset! processing? false)))
(reg-event-db :store-value-error
(fn [db _]
(reset! processing? false)))
(fn button-render []
[:button {:class (when @processing? "processing")
:on-click (fn []
(reset! processing? true)
(dispatch [:store-value 123]))}])))
然而,这是行不通的。看起来,re-frame不允许每个事件有多个事件处理程序。相反,对单个事件id的reg event db
的后续调用将替换以前的事件处理程序
那么你们是如何处理这种情况的呢?我认为reg event fx
()可能确实有助于解决您的问题
您可以添加监视应用程序状态的订阅,例如
(rf/reg-sub
:app-state
(fn [db]
(get db :app-state)))
并将其添加到按钮中,可能带有状态功能,例如
(defn btn-state [state]
(if (= state :processing)
"processing"))
然后在AJAX处理程序中,您可以添加一个fx来更新状态-
(reg-event-fx ;; -fx registration, not -db registration
:ajax-success
(fn [{:keys [db]} [_ result]]
{:db (assoc db :app-state :default)
:dispatch [:store-value-success result]}))
(reg-event-fx ;; -fx registration, not -db registration
:ajax-error
(fn [{:keys [db]} [_ result]]
{:db (assoc db :app-state :default)
:dispatch [:store-value-error result]}))
并更新AJAX处理程序
(reg-event-db :store-value
(fn [db [_ value]]
(do-ajax-store value
:on-success #(dispatch [:ajax-success %])
:on-error #(dispatch [:ajax-error %])
db))
这将是通过-fx处理它的一种方法。我认为您已经开始看到跟踪应用程序状态的必要性,我认为将其添加到订阅中将有助于降低复杂性,在这一点上,您的按钮渲染将大大简化
(defn button []
[:button {:class (btn-state @app-state)
:on-click (dispatch [:store-value 123]))}])))
正如其他人提到的,我建议使用并使处理?
成为您全局状态的一部分。代码如下所示:
(defn button []
(let [processing? (reagent/atom false)]
(reg-event-db :store-value-success
(fn [db _]
(reset! processing? false)))
(reg-event-db :store-value-error
(fn [db _]
(reset! processing? false)))
(fn button-render []
[:button {:class (when @processing? "processing")
:on-click (fn []
(reset! processing? true)
(dispatch [:store-value 123]))}])))
活动:
(reg-event-fx
:request
(fn [{:keys [db]} [_ method url data]]
{:http-xhrio {:method method
:uri url
:params data
:format (ajax/json-request-format)
:response-format (ajax/json-response-format {:keywords? true})
:on-success [:success-response method url]
:on-failure [:error-response method url]}
:db (assoc db :processing? true)}))
(reg-event-db
:success-response
(fn [db [_ method url result]]
(assoc db :foobar response
:processing? false)}))
(reg-event-db
:error
(fn [db [_ method url result]]
(assoc db :foobar nil
:last-error result
:processing? false)}))
订阅:
(reg-sub
:processing
(fn [db _]
(:processing? db)))
视图:
提示:您可以在所有请求中重复使用此代码。另外,请看一看谢谢,我已经注意到了这一点。然而,我看不出这是如何解决所描述的问题的。我遗漏了什么吗?不,只是想引起你的注意。:)啊,我明白了:)。非常感谢。很抱歉回答晚了。然而,我认为您提供的代码确实比我所拥有的更干净。虽然我觉得将按钮本地状态提升为全局状态有些尴尬。但也许我对这种状态的理解是不正确的,因为它不是真正的按钮本地状态,而是应用程序全局状态,因为它是关于正在进行的AJAX调用,而不仅仅是关于按钮本身;)。