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?

andre 2021-04-19T09:07:02.200400Z

Hey lovely re-framers πŸ™‚ re-frisk 1.5.0 is here

andre 2021-04-19T09:07:06.200600Z

you can try it

andre 2021-04-19T09:07:21.200800Z

[re-frisk "1.5.0"]

andre 2021-04-19T09:07:38.201Z

β€’ render and force update traces β€’ watching keys in app-db β€’ view by subs filtering

andre 2021-04-19T09:08:29.201500Z

it doesn't show views names in the demo because of optimization, but they will be shown in dev

p-himik 2021-04-19T09:20:37.201600Z

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

Ronny Li 2021-04-19T23:13:43.204700Z

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!

prnc 2021-04-20T12:42:49.211100Z

is this > (def event:event-name ::event-name) some kind of namespacing by convention, i.e. the use of : in the symbol there? @emccue

emccue 2021-04-20T14:40:52.214300Z


emccue 2021-04-20T14:48:58.214900Z

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

emccue 2021-04-20T14:55:01.215500Z

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 %))}])

p-himik 2021-04-20T15:02:17.216100Z

Where would you use user-typed without dispatch?

emccue 2021-04-20T16:28:11.216600Z

in the tests like bove

p-himik 2021-04-20T16:29:27.216800Z

Ah, I see now, thanks.

p-himik 2021-04-19T23:19:04.204800Z

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.

p-himik 2021-04-19T23:19:24.205Z

But it won't be robust because you can create and use subscriptions and events dynamically.

emccue 2021-04-19T23:20:34.205200Z

@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

Ronny Li 2021-04-19T23:21:10.205400Z

thanks everyone! Great suggestions!

emccue 2021-04-19T23:21:11.205600Z

(def get-stuff [db id]

  (fn [db id]
    (get-stuff db id)))

(defn subscription:get-stuff
  (rf/subscribe [::stuff id]))

emccue 2021-04-19T23:23:10.206Z

keeping in mind I define my events like this

Lu 2021-04-19T23:24:17.206200Z

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

emccue 2021-04-19T23:24:59.206400Z

(def event:event-name ::event-name)

(defn event-name [args]
  [event:event-name args])

(defn handler:event-name
  [{:keys [db]} args]
  {:db ...
   :fx ...})


emccue 2021-04-19T23:25:06.206600Z

so i'm maybe a little crazy

p-himik 2021-04-19T23:25:23.206800Z

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)

Lu 2021-04-19T23:26:11.207100Z

Yeah true.. I mean definitely something to avoid but it won’t harm the app πŸ˜…

Ronny Li 2021-04-19T23:27:20.207500Z

@emccue very interesting... A little crazy but maybe that's the genius behind it :P

emccue 2021-04-19T23:27:52.207700Z

I do have a justification, but the world isn't ready

p-himik 2021-04-19T23:28:58.207900Z

Let me guess - so you always require the necessary namespace with the right calls to reg-event-*? :)

Ronny Li 2021-04-19T23:35:14.208200Z

I'm very curious now!

p-himik 2021-04-19T23:38:45.208400Z

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 %])}])

emccue 2021-04-19T23:53:32.208800Z

Thats part of it, but more importantly we only ever use :db and :fx so we can compose event handlers and write tests like

emccue 2021-04-19T23:57:09.209Z

(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))))))

emccue 2021-04-19T23:58:27.209300Z

and moving towards banning use of :dispatch within event handlers so we can always make these assertions and state changes happen "atomically"