This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-08
Channels
- # adventofcode (49)
- # babashka (21)
- # babashka-sci-dev (12)
- # beginners (250)
- # calva (23)
- # cider (6)
- # clj-kondo (11)
- # cljsrn (8)
- # clojure (129)
- # clojure-europe (50)
- # clojure-france (8)
- # clojure-italy (6)
- # clojure-nl (14)
- # clojure-romania (7)
- # clojure-spec (21)
- # clojure-uk (3)
- # clojurescript (17)
- # conjure (1)
- # core-async (40)
- # core-logic (24)
- # core-typed (7)
- # datavis (2)
- # datomic (2)
- # emacs (29)
- # fulcro (10)
- # graalvm (6)
- # graphql (24)
- # gratitude (6)
- # jobs (1)
- # lsp (9)
- # malli (6)
- # missionary (1)
- # nextjournal (46)
- # off-topic (2)
- # other-languages (3)
- # pathom (5)
- # portal (2)
- # re-frame (37)
- # remote-jobs (1)
- # shadow-cljs (15)
- # spacemacs (9)
- # testing (6)
- # tools-deps (13)
- # vim (32)
- # xtdb (16)
hello devs, I'm trying to write an interceptor which upon ajax-failure event will analyse the event. If the event is of unauthenticated nature. I'd like to erase the ajax-failure event and replace it (modify the context somehow) with dedicated ::unauthenticated event. This way I could have common behaviour to deal with it. What is the best way to do it?
(re-frame.core/->interceptor
:id :detect-unauthorized
:before (fn [context]
(let [coeffects (:coeffects context)
initial {:db (:db coeffects)
:event (:event coeffects)
:fx []}
result (cond-> initial
(-> coeffects :event first #{::failure-domain-result})
(#(do
(prn ":detect-unauthorized-before")
(-> %
(assoc :dispatch [::unauthorized])))))
_ (prn result)
effects (select-keys result [:db :fx])]
(assoc context :effects effects)))
I don't think it's a good use of an interceptor. For such behavior, I would definitely write a custom effect that wraps the AJAX effect you're already using.
how to write a mechanism (via interceptor or other) which upon detection of some event (potentially using its params) erase that event and emit an alternative one?
(def detect-unauthorized
(re-frame.core/->interceptor
:id :detect-unauthorized
:after (fn [context]
(if (-> context :coeffects :event first #{::failure-domain-result})
(assoc-in context [:effects :dispatch] [::unauthorized])
context))))
(re-frame.core/reg-global-interceptor detect-unauthorized)
@U2FRKM4TW thank you for hints
Well, that only works for events that are dispatched via the :dispatch
effect.
However, there are events that are dispatched using dispatch
, dispatch-sync
, :dispatch-n
, :fx
, maybe even potentially modifying the queue directly (don't do that of course).
A global interceptor with :before
would handle all such cases simply because it works right on top of the events that are about to be handled, and you can dynamically replace that handling.
so the global interceptor correctly dispatches the ::unauthorized
when it gets unauth
and the navigation correctly navigates to :logout
route
the ::failure-domain-result
event happens anyway and the :app-db
gets updated unfortunately
Don't do that - it's a vain task given how it won't address all the rest of the issues.
I appreciate the good advice. Which I agree with. But I still want to understand how it's done.
since context is just a map, I'd like to understand how the event dispatching mechanism still works after I've updated the context.
There's no one to better answer that question better than the re-frame source code itself. :)
@U2FRKM4TW after reading the source code and much thinking, I believe messing with events is bad idea. Basically it's not clean.
Instead I use https://github.com/JulianBirch/cljs-ajax/blob/master/docs/interceptors.md (different kind of interceptors) to handle the unauth case.
Not sure what you mean by "not clean" in this case. Altering the interceptor chain of a particular event doesn't result in any side-effects or loss of referential transparency.
But if the library that you're using can already handle your use-case, then it's definitely the way to do. I was assuming there was no such functionality.
Also, I promised to come up with an example of such a global interceptor that replace one event with the other, but if you don't really need it I won't do that because writing it requires some careful thinking and most likely using private re-frame API.
look, the event dispatch is not just mutating the context, but it enqueues the event object via router to the queue
> against the re-frame nature
I wouldn't say so, it's even documented to some extent: https://github.com/day8/re-frame/blob/master/docs/Interceptors.md#self-modifying
> the event dispatch is not just mutating the context
It's not mutating, it's creating a brand new context. Like every single interceptor, even the built-in path
. All according to the nature of immutable data - all is fine here.
> enqueues the event object via router to the queue
Not in what I had in mind - it would simply modify the documented :queue
value of the context, that's it.
> so manipulating the context can't emulate the event not happening. This is a false statement, but with an asterisk. You can replace the interceptor that actually invokes the event handler function with a no-op, along with all the other interceptors that particular event handler registration uses. But you can't make it seem as if the event was never in the queue in the first place. Fortunately, not a lot of things care about that.