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.
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.