Is there a way to detect an error in an effect? I would like to add a custom error handler for the effect that I donβt control and was wondering if this was possible?
Hey lovely re-framers π re-frisk 1.5.0 is here
you can try it https://flexsurfer.github.io/conduit-re-frisk-demo/
[re-frisk "1.5.0"]
β’ render and force update traces β’ watching keys in app-db β’ view by subs filtering
it doesn't show views names in the demo because of optimization, but they will be shown in dev
There's not built-in functionality, but you could wrap that third-party effect handler with your own error handling by first retrieving it with (re-frame.registrar/get-handler :fx that-effect-id)
and then just calling it as a function within your own effect handler
Do note that re-frame.registrar/get-handler
is not a public API.
thanks, nice option
Hi everyone, what's the best practice for checking for mistakes in events and subscriptions? For example, I recently deleted a subscription that was still being used (by accident of course). It would be great to set up something that automatically alerts me to these inconsistencies in the future!
is this
> (def event:event-name ::event-name)
some kind of namespacing by convention, i.e. the use of :
in the symbol there? @emccue
yeah
might macro it up at some point if the pattern holds, but for now biting the bullet of typing so we don't get hard locked in
so for @p-himik's example we would do this
;; Events
(def event:user-typed ::user-typed)
(defn user-typed [text]
[event:user-typed text])
(defn handler:user-typed
[{:keys [db]} [_ text]]
{:db (update db ::model/page-state
:user-input assoc text)
:fx []})
(rf/reg-event-fx event:user-typed handler:user-typed)
;; view
(defn input [{:keys [user-input]}]
[:input {:value user-input
:on-change #(rf/dispatch (events/user-typed %))}])
Where would you use user-typed
without dispatch
?
in the tests like bove
Ah, I see now, thanks.
If you mean something like static analysis to detect such things, then maybe #clj-kondo could be used, or at least something that it uses itself.
But it won't be robust because you can create and use subscriptions and events dynamically.
@ronny463 I am in no way who you should go to for best practices, but anything you can tie to a var you can get compiler error if you mess up
thanks everyone! Great suggestions!
(def get-stuff [db id]
...)
(rf/reg-sub
::stuff
(fn [db id]
(get-stuff db id)))
(defn subscription:get-stuff
[id]
(rf/subscribe [::stuff id]))
keeping in mind I define my events like this
Actually, tracking missing events/subs should be pretty straight forward, as you get subscription nil
and event not found
errors logged in the console.. Iβve never had to spend more than a few seconds to realize what was missing
(def event:event-name ::event-name)
(defn event-name [args]
[event:event-name args])
(defn handler:event-name
[{:keys [db]} args]
{:db ...
:fx ...})
(rf/reg-event-fx
event:event-name
handler:event-name)
so i'm maybe a little crazy
Yeah, but that works only if something does happen that uses that sub or event. If you never click a particular button and don't have a test for it, it might end up being sent to the production. (answering to Lu)
Yeah true.. I mean definitely something to avoid but it wonβt harm the app π
@emccue very interesting... A little crazy but maybe that's the genius behind it :P
I do have a justification, but the world isn't ready
Let me guess - so you always require
the necessary namespace with the right calls to reg-event-*
? :)
I'm very curious now!
I do something similar but more lazy and less robust:
(ns some.stuff
(:require [re-frame.core :as rf]))
(rf/reg-sub ::value
(fn [db _]
(:value db)))
(rf/reg-event-db ::set-value
(fn [db [_ new-value]]
(assoc db :value new-value)))
(ns other.things
(:require [re-frame.core :as rf] [some.stuff :as stuff]))
(defn input []
[:input {:value @(rf/subscribe [::stuff/value]), :on-change #(rf/dispatch [::stuff/set-value %])}])
Thats part of it, but more importantly we only ever use :db and :fx so we can compose event handlers and write tests like
(let [process (custom-compose
#(handler:focus-on-field % (focus-on-field))
#(handler:typed-in-field % (typed-in-field "a"))
#(handler:typed-in-field % (typed-in-field "b")))]
(is (= (:db (process (...initial db state)))
...asserted db state...))
(is (contains-some-effect-we-want-to-assert
(:fx (process (...initial db state))))))
and moving towards banning use of :dispatch within event handlers so we can always make these assertions and state changes happen "atomically"