2017-01-10 8 views
0

私は再フレームが大好きですが、AJAXレスポンスを処理するための素敵なパターンを見つけるのに少し苦労しています。Clojureの再フレームでAJAXの成功/エラー応答を処理する方法は?

私の状況は以下の通りです:

私は例えば、その呼び出しが成功したかどうかに応じて、いくつかの他のグローバルイベントハンドラにいくつかの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を知っています。簡潔さのために、私はここでそれを避けています、そして、それは私の問題のために何の違いもないと思うからです)。

のでように私はまた、:store-valueイベントをトリガする可能性がある(複数の異なる)UIコンポーネントを有する:

(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コールはまだ進行中であるかどうかはわかりません。

さて、適切なパターンは、AJAX呼び出しが完了した後にfalseに戻っprocessing?フラグをリセットするためにイベント:store-value-success:store-value-errorに反応をbutton成分を持つためにここ何ですか?

現在、私はコールバックを渡すことでこの問題を回避していますが、実際にそこに属していないものでイベントハンドラのコードを混乱させるため、実際には醜いようです。私が考えてきた

最善の解決策は、このように、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]))}]))) 

しかし、 、それは動作しません。再フレームはイベントごとに複数のイベントハンドラを許可しません。代わりに、1つの単一のイベントIDでreg-event-dbを後で呼び出すと、前のイベントハンドラーが置き換えられます。

こういう状況にどうやって対処していますか?

+1

また、https://github.com/Day8/re-frame-http-fx –

+0

をご覧ください。ありがとうございます、私はそれを認識しています。しかし、私はその問題をどのように解決するのか分かりません。何か不足していますか? – Oliver

+0

いいえ、ちょうどそれをあなたの注意に持っていきたいと思っていました。 :) –

答えて

1

私はreg-event-fxsrc)だとあなたの問題を解決するのに役立つかもしれないと思います。

アプリ状態を監視するサブスクリプションを追加できます。たとえば、

(rf/reg-sub 
    :app-state 
    (fn [db] 
    (get db :app-state))) 

これをボタンに追加します。これはおそらく状態関数などで行います。

(defn btn-state [state] 
    (if (= state :processing) 
    "processing")) 

そして、AJAXハンドラで、あなたは状態 -

(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を追加することができますこれは、処理するための一つの方法だろうそれは-fx経由です。私はあなたが既にアプリケーションの状態を追跡する必要性を見始めていると思います。サブスクリプションにそれを取り入れることは、複雑さに役立ちます。その時点でボタンのレンダリングは大幅に簡素化されます。

(defn button [] 
     [:button {:class (btn-state @app-state) 
       :on-click (dispatch [:store-value 123]))}]))) 
+0

遅れて申し訳ありません。 しかし、あなたが提供するコードは、実際に私が持っていたよりもきれいだと思います。 私は、ボタンローカルの状態をグローバルな状態にすることはやや面倒ですが、しかし、本当はボタンローカルなのではなく、実際にはアプリケーション全体の状態なので、その状態に関する私の考えはちょうど間違っていたかもしれません。なぜなら、それはAJAXコールのことです。 – Oliver

1

他の人が述べたように、私は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]))}]))) 

ヒント:あなたはすべてのあなたのリクエストでこのコードを再利用することができ、コードは次のようになります。

関連する問題