Skip to content

Commit

Permalink
Explain why event-fx handlers can't return cofx maps
Browse files Browse the repository at this point in the history
  • Loading branch information
kimo-k committed Dec 7, 2023
1 parent 81e8f30 commit f5c3edd
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
47 changes: 47 additions & 0 deletions docs/FAQs/use-cofx-as-fx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!-- leave this H1 here. It stops mkdocs putting in a Title at the top.
It needs to be at the top of the file otherwise it breaks the
table of contents on the right hand side. -->
#

## 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.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/re_frame/fx.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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 ------------------------------------------------

Expand Down

0 comments on commit f5c3edd

Please sign in to comment.