This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-24
Channels
- # announcements (4)
- # asami (5)
- # babashka (20)
- # beginners (94)
- # bristol-clojurians (1)
- # calva (23)
- # cider (2)
- # clj-commons (3)
- # clj-kondo (43)
- # cljfx (2)
- # cljs-dev (13)
- # clojure (112)
- # clojure-dev (44)
- # clojure-europe (17)
- # clojure-nl (5)
- # clojure-poland (12)
- # clojure-spec (2)
- # clojure-uk (3)
- # clojurebridge (1)
- # clojurescript (92)
- # cursive (17)
- # data-science (8)
- # datahike (1)
- # datalevin (1)
- # datomic (3)
- # deps-new (7)
- # events (2)
- # fulcro (40)
- # graalvm (110)
- # holy-lambda (16)
- # introduce-yourself (1)
- # lsp (13)
- # malli (8)
- # missionary (12)
- # off-topic (10)
- # pathom (13)
- # polylith (10)
- # portal (28)
- # re-frame (37)
- # reitit (1)
- # releases (1)
- # shadow-cljs (30)
- # spacemacs (1)
- # tools-deps (9)
- # xtdb (10)
Hello, I'm using re-frame with shadow-cljs and for authentication using JWT. In the login/registration API I'm getting JWT along with user info so, I'm storing it in app-db as user-secret and user. Now, when I want to call any API I'm passing that token in headers so, it will verify it so, that's not an issue. But I also want to check whether user and user-secret is present in app-db when user navigate the route (Not in all route like I don't want to check that in login/registration). What is the best way of doing it? Currently, which routes I have to check I pass controllers and start & inside that dispatching an event. Eg:
["/book/add" {:name :add-book
:view book/add-book
:controllers [{:start (fn [_]
(rf/dispatch [:check-authentication]))}]}]
And check authentication is like below.
(rf/reg-event-fx
:check-authentication
(fn [{:keys [db]}]
(if (empty? (:user db))
{:navigate! [:login]})))
Any best alternative for doing this ?
Thanks.If the only thing that actually does the navigation itself is the :navigate!
effect, then the bare minimum solution would be to implement a global interceptor, check there whether :navigate!
is present, and replace its argument with [:login]
if there's no user information.
If you can also navigate via regular links, then see your navigation/routing library's documentation - perhaps, it will allow you to add a global controller that would be triggered for all the routes. If not, then just creates routes as you do now, and simply add the same controller to every route with mapv
or so.
Does re-frame run subscription handlers synchronously?
Depends on what you mean. They are not run concurrently, but there's no guarantee about their order.
@U2FRKM4TW thanks for your answer. We have a sub handler that takes way too long time that we'd expect. Our guess is that the browser doesn't give the cpu control to that subscription handler often enough. Does that make sense?
eg, re-frame runs 10% of the handler, saves the execution stack, gives the control back to other parts, then 10% again, etc
Re-frame itself doesn't do it. But it can happen if your sub uses promises or async JS functions, although that would be strange - you would receive a promise as a result of that sub.
I see, thank you. We don't have anything like these in our codebase.
Are you sure you don't have a CPU hog somewhere that simply prevents your page from re-rendering?
you mean within the browser?
there are dispatchs happening, I think 2
That doesn't really answer the question. During a CPU hog you can't do anything. If you see that your page is not responsive, I would profile it using your browser's devtools and see what's going on. Apart from that, hard to say anything without having the actual code.
the subscription handler itself is doing: 1. check the local cache (app-db) if the requested entity is present 2. if not, fetch the data (dispatch) and display a loader 3. if the data is present, reconstruct (denormalize) the requested entity (a graph with 20k+ relationships)
the ajax request itself takes ~300 ms to execute, but the whole process takes around 5 to 7 seconds
the page seems responsive, but the page is just a loader, so we can't really tell
it's what's recommended in the re-frame docs though, "how to load external data", the subscription handler runs a dispatch
https://github.com/day8/re-frame/blob/master/docs/Subscribing-To-External-Data.md
oh, right
it shouldn't really be an issue, though?
it's very convenient and we'd like to avoid having to change that pattern
No clue, I have no idea what you're actually doing. And I find it rather hard to reason about impure subscription and even handlers most of the time. Have you tried using a global interceptor to conditionally load the required data?
The pattern in question is: subscribe to data -> data not present, dispatch the http request (in the sub handler)
I'll look into global interceptors, not sure it'll help, I thought it's about event handlers, not subscriptions
Right. You never subscribe to some data out of the blue. It always happens as a consequence of some events. So you can move data loading to a global interceptor that would simply watch for those events, either by event IDs (and if you know them for sure, it might be better to use a regular interceptor with just those events) or by some marker.
An example - you need to load data for a table when that table is first shown. But the table is visible only when the :table-visible?
key in the app-db is set. So, you monitor that key in a global interceptor and load the data when it becomes not false-y.
I'd be intercepting a dispatch, right? In your example, the dispatch in question would be [:open-table]
?
If so, we can't do that, that would imply a heavy refactoring. All of our app is dependant on the pattern shown on the doc I sent earlier.
You'd be intercepting an event. Which might not come from a dispatch, but usually they do come from there, yes.
From where would it come from, if not an dispatch?
You can modify the event queue. But I've never seen such a thing being done, and I can't think of any reason to do that.
I see. Then I guess we'll keep the "dispatch in the subscription handler" pattern. This shouldn't cause any performance issue, anyway.
One thing a global interceptor might help with is just seeing where those 5 to 7 seconds are going. I suspect a race condition in which the data stars just happen to align eventually.
Does re-frame guarantee that metadata on a dispatched event will be passed to any downstream handler function (e.g., event handler, post event callback)?