From f5c3eddfdf8a26d7c94f158edcdaf454c3fca248 Mon Sep 17 00:00:00 2001 From: Kimo Knowles Date: Thu, 7 Dec 2023 20:32:35 +0100 Subject: [PATCH] Explain why event-fx handlers can't return cofx maps --- docs/FAQs/use-cofx-as-fx.md | 47 +++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + src/re_frame/fx.cljc | 8 ++++++- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 docs/FAQs/use-cofx-as-fx.md diff --git a/docs/FAQs/use-cofx-as-fx.md b/docs/FAQs/use-cofx-as-fx.md new file mode 100644 index 000000000..c26cc3ec4 --- /dev/null +++ b/docs/FAQs/use-cofx-as-fx.md @@ -0,0 +1,47 @@ + +# + +## Question + +With `reg-event-fx`, why can't my handler function just update the first argument (i.e. the `cofx` map) and pass it on? + +When I try, I get a warning, such as: `no handler registered for effect: :event. Ignoring.` + +## Answer + +Effects simply aren't coeffects. + +To fix this warning, just declare a new map of effects. For instance: + +```clj +(reg-event-fx ::cow-clicked + (fn [{:keys [db] :as cofx} _] + {:db (update db :clicks inc)})) +``` + +## Context + +This seems like it would work, if you're used to using `reg-event-db` this way. +Such a `db` handler behaves like a reducing function: + +```clj +(reg-event-db ::cow-clicked-db + (fn [db _] (update db :clicks inc))) +``` + +Doing a similar thing to a coeffect map causes the warning, however, not to mention possible unintended effects: + +```clj +(reg-event-fx ::cow-clicked-bad + (fn [cofx _] (update-in cofx [:db :clicks] inc))) +``` + +With `reg-event-fx`, you receive a map of coeffect values, and you're expected to return a map of effect values. +It's a coincidence that `:db` is the name of both an effect and a coeffect. +But re-frame adds other coeffects, such as `:event`, which it does *not* consider effects. + +So your handler ends up doing `(update-in {:db {:clicks 0} :event [::cow-clicked-bad] :your-other-coeffect 25} ...)`. + +Any coeffects you declare cause this problem, too. You might have a coeffect, like `:db`, which shares its name with an effect. But that's a deliberate design decision, not a default. diff --git a/mkdocs.yml b/mkdocs.yml index fc6be86ae..02bcfd084 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,6 +84,7 @@ nav: - "Why is my input field laggy?": FAQs/laggy-input.md - "How long after I do a dispatch does the event get handled?": FAQs/When-Does-Dispatch-Happen.md - "How can I use a subscription in an Event Handler": FAQs/UseASubscriptionInAnEventHandler.md + - "Why can't I turn a `cofx` map into an `fx` map?": FAQs/use-cofx-as-fx.md - "How do I use logging method X": FAQs/Logging.md - "Dispatched Events Are Null": FAQs/Null-Dispatched-Events.md - "Why do we need to clear the subscription cache when reloading with Figwheel?": FAQs/Why-Clear-Sub-Cache.md diff --git a/src/re_frame/fx.cljc b/src/re_frame/fx.cljc index 7a0ab6b9f..17cc27ae2 100644 --- a/src/re_frame/fx.cljc +++ b/src/re_frame/fx.cljc @@ -56,7 +56,13 @@ (doseq [[effect-key effect-value] effects-without-db] (if-let [effect-fn (get-handler kind effect-key false)] (effect-fn effect-value) - (console :warn "re-frame: no handler registered for effect:" effect-key ". Ignoring.")))))))) + (console :warn + "re-frame: no handler registered for effect:" + effect-key + ". Ignoring." + (when (= :event effect-key) + (str "You may be trying to return a coeffect map from an event-fx handler. " + "See https://day8.github.io/re-frame/use-cofx-as-fx/")))))))))) ;; -- Builtin Effect Handlers ------------------------------------------------