应该如何处理 Clojure 重构中的 AJAX success/error 响应?
How should one handle AJAX success/error responses in Clojure re-frame?
我喜欢重新构建框架,但我意识到我在寻找处理 AJAX 响应的良好模式时遇到了一些麻烦。
我的情况是这样的:
我有一个 "global" 事件处理程序,它触发一些 AJAX 调用并分派到其他一些全局事件处理程序,具体取决于该调用是否成功,例如:
(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]))}])))
所以在这种情况下,组件具有本地状态 (processing?
),这应该取决于 AJAX 调用是否仍在进行中。
现在,让 button
组件对事件 :store-value-success
和 :store-value-error
做出反应以便将 processing?
标志重置回false
AJAX 调用结束后?
目前,我正在通过向下传递回调来解决这个问题,但这看起来真的很难看,因为它使事件处理程序的代码变得杂乱无章。
我想到的最佳解决方案是让 button
组件能够连接到 :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]))}])))
但是,这不起作用。看起来,重新框架不允许每个事件有多个事件处理程序。相反,对单个事件 ID 的后续调用 reg-event-db
将替换前一个事件处理程序。
你们是怎么处理这种情况的?
我认为 reg-event-fx
(src) 可能确实有助于解决您的问题。
您可以添加观看 app-state 的订阅,例如
(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]))}])))
正如其他人所提到的,我建议使用 http-fx 并使 processing?
成为全局状态的一部分。代码如下所示:
事件:
(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)))
查看:
(defn button []
(let [processing? @(rf/subscribe [:processing])]
[:button {:class (when processing? "processing")
:on-click #(dispatch [:store-value 123]))}])))
提示:您可以在所有请求中重复使用此代码。
我喜欢重新构建框架,但我意识到我在寻找处理 AJAX 响应的良好模式时遇到了一些麻烦。
我的情况是这样的:
我有一个 "global" 事件处理程序,它触发一些 AJAX 调用并分派到其他一些全局事件处理程序,具体取决于该调用是否成功,例如:
(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]))}])))
所以在这种情况下,组件具有本地状态 (processing?
),这应该取决于 AJAX 调用是否仍在进行中。
现在,让 button
组件对事件 :store-value-success
和 :store-value-error
做出反应以便将 processing?
标志重置回false
AJAX 调用结束后?
目前,我正在通过向下传递回调来解决这个问题,但这看起来真的很难看,因为它使事件处理程序的代码变得杂乱无章。
我想到的最佳解决方案是让 button
组件能够连接到 :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]))}])))
但是,这不起作用。看起来,重新框架不允许每个事件有多个事件处理程序。相反,对单个事件 ID 的后续调用 reg-event-db
将替换前一个事件处理程序。
你们是怎么处理这种情况的?
我认为 reg-event-fx
(src) 可能确实有助于解决您的问题。
您可以添加观看 app-state 的订阅,例如
(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]))}])))
正如其他人所提到的,我建议使用 http-fx 并使 processing?
成为全局状态的一部分。代码如下所示:
事件:
(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)))
查看:
(defn button []
(let [processing? @(rf/subscribe [:processing])]
[:button {:class (when processing? "processing")
:on-click #(dispatch [:store-value 123]))}])))
提示:您可以在所有请求中重复使用此代码。