Fork me on GitHub
Quentin Le Guennec08:06:09

Hello, what would be the equivalent of re-frame subscriptions in fulcro? I'm guessing it would be resolvers + injecting the resolver output name in a component query?


Someone was working on separating the re-frame subs out of re-frame, just for working with fulcro. But it is going to be tricky. The re-frame model is that components directly get the data, not from parents. But at the same time they do not know the db structure. In fulcro it's the opposite. And there are no queries for derived data, but everything really needs to be put into the db


Nevertheless I'd say that the bigger differences are in interceptors, or lack of.

Quentin Le Guennec11:06:51

Can't I use front side resolvers for that?


You mean pathom resolvers?


They are not reactive, though


And also the graph model, where the client/component knows how to traverse the graph to get from given root to needed leaves, is very different from the subscription model where the data provider "just knows" the full db and can provide the named information

Jakub Holý (HolyJak)12:06:14

According to Tony, he rarely needs to deal with derived data like that. Most of the time he just computes them in place, in the render function (ie defsc body). Obviously it works fine for many real-world cases. It just requires a different way of thinking. Sometimes recomputing on every render is not practical. Here it is interesting to study RAD reports that have raw data but also derived sorted and filtered data. They use UISM to trigger the re-computation of these (when the raw data is (re)loaded or filter/sort criteria changed). So this is another approach. Finally you can yourself compute the derived data at - and that is tricky - all the points where that is relevant, i.e. the load call and mutations. I imagine you could also (mis)use pre-merge to compute derived data, but you'd need to keep it updated if you later change those data. So nothing like subscriptions - but we rarely need it because we just think about the problem and solution differently. Also, @U051V5LLP has created a standalone subscriptions library that can be used with Fulcro, here is an example


fulcro components are already things that react to data changes and perform some side effect (i.e. rendering) right? can't you just transact from render to write derived data back into the db?


Sure, that works. But it needs more than just having the pathom resolvers


That is, when the first layer of the data changes, the mutation also needs to know what derived data needs to be refreshed, unlike in the re-frame model where the subscriptions get their dependencies pushed to them


With the component driven model you might run into duplicated calculations (with more than two instances of the component rendering), or perhaps even loops. But if the duplicated work is acceptable, as well as components knowing data they need only for the derivation, then it might make sense to store the derived data in the component local state instead of the fulcro db


by components I mean ones used specifically for rendering this derived data. they would just be children of root or something and not actually render any UI


That doesn't really matter for the duplication or possibility of loops, though


It is doable, certainly, and choosing between that, local state (react setState), and handling the derived data in the mutation depends on what the other app looks like. And I suppose from personal preferences for architecture


yeah, that's just a matter of being mindful of your code.. does re-frame do something to prevent that sort of mistake?


It's been a while, but there's definitely no duplication (well, unless you create two subscriptions that calculate the same thing) and I think it won't allow loops either


I guess if it compiles all the dependencies ahead of time and forms some DAG it could be smart about it


I think it even handles dependency synchronization, but that I'm pretty unsure about

Jakub Holý (HolyJak)13:06:21

Notice I was not suggesting to use local state at all. Ie. compute on render w/o caching


@U0111PVCS8P this library allows using subscriptions in fulcro. Some rationale is here (specifically for use with fulcro) some background: I've been on the fulcro library journey since Om classic, I am building apps with lots of derived data where the domain models are graphs and trees, not lists and 2d tables. As my data manipulations on the client got more complex I found the use of idents and queries + pre-merge for derived state to be incidental complexity, and specifically I had situations where my UI was stale compared to what was in the fulcro db. I had the chance to learn re-frame for work and saw all those problems go away with subscriptions. All I wanted to do was manipulate data and feed it to components, not have to figure out how to "compose to root". The integration in that library lets you get the best of both: fulcro for normalizing your "ground truth" domain entities and subscriptions for derived data. No stale UI in sight, no data transformation in your views. The re-frame docs have more info on this (

👀 1
Quentin Le Guennec08:06:00

(my question is about browser side only, not full stack)


I have an app based on fulcro template. And I am using websockets. In some resolvers I am parsing jwt token found in authentication header. So how to found headers? HTTP (defn wrap-api [handler uri] (fn [request] (if (= uri (:uri request)) (handle-api-request (:transit-params request) (fn [tx] (parser {*:ring/request* request} tx))) (handler request)))) WEB SOCKETS: *:request* (:ring-req event) ; legacy. might be removed I can change my code based on template or get authorization: (or (get-in env [:ring/request :headers "authorization"]) (get-in env [:request :headers "authorization"])) But I am asking about comment "legacy might be removed". Is there a better way to get headers in resolver behind websockets?


probably not going to be removed. The main trick is that with websockets you only get the headers once, on initial connect. If you change them (e.g. via some auth sequence) then you have to call reconnect on the websocket to have it re-establish the connection with the new headers.