Search code examples
clojurescriptreagentre-frame

Dispatch after last dispatch chain finishes


What the dispatch order should look like:

;; Initial Data
(dispatch [:http/get-bar])
;; We click something to update foo
(dispatch [:http/update-foo])
;; :success handler gets run:
(dispatch [:http-success/update-foo])
;; Foo data influences bar data, we want to get-bar again after foo updates
(dispatch [:http/get-bar])

If we have something like this:

{:on-click
 (fn []
   (dispatch [:http/update-foo])
   (dispatch [:http/get-bar]))}

The order will really look like:

[[:http/get-bar]
 [:http/update-foo]
 [:http/get-bar]
 [:http-success/update-foo]]

We are unable to guarantee the update succeeds before we get bar again. It is possible to dispatch :http/get-bar as part of :http-success/update-foo, but hard-coding makes things less flexible. In my specific use case, I have a modal component that is used on two different pages. On clicking save, both will dispatch to [:http/update-foo] but one page will follow up with [:http/get-bar] and another will follow up with [:http/get-baz], both of which need foo to finish updating first.


Solution

  • This sounds to me like something you can solve with re-frame-async-flow-fx.

    Your code could look something like this:

    (defn modal-flow [dispatch-after]
      {:first-dispatch [:http/update-foo]
       :rules [
         {:when :seen? :events :http/update-foo-success :dispatch [dispatch-after]}
       ]})
    
    (re-frame/reg-event-fx
      :modal-1
      (fn [_ _]
        {:async (modal-flow :get/update-foo)}))
    
    (re-frame/reg-event-fx
      :modal-2
      (fn [_ _]
        {:async (modal-flow :get/update-baz)}))
    

    Async flows are really powerful for crafting these kinds of dependencies, allowing you to keep your individual handlers free from hardcoded (or awkwardly parameterized) dispatch-after values.