re-frame

https://github.com/Day8/re-frame/blob/master/docs/README.md https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md
Richie 2021-05-11T00:11:34.437300Z

Oh, ok. I have code in my event handler that computes a value from the db and then the event handler computes an effect from that value. I was trying to move the code that computes the value out of that function. Something like on-changes but in the :before position instead of :after. I’m just not sure how to refactor my code and I thought I’d try interceptors.

p-himik 2021-05-11T00:14:37.437500Z

Sounds like you can simply compute that within the event handler itself, no?

p-himik 2021-05-11T00:16:08.437700Z

The concrete problem in the scenario above is that db-handler->interceptor is a :before interceptor and path is both :before and :after. So path changes the :db effect in its :after phase.

Richie 2021-05-11T00:21:41.437900Z

Yes, I can. I think the first thing that made me unhappy is seeing re-frame docs https://day8.github.io/re-frame/correcting-a-wrong/#a-final-faq criticizing hard coding db paths. In the view, I enjoy subscribing to data that doesn’t really exist in the db but is computed from the db. I was trying to put those two ideas together.

Richie 2021-05-11T00:25:05.438200Z

Right. I do want to get {:db {:p {:a {:th 1}}}} out of it. I was surprised that I got the same result in both orderings. I don’t expect it to work with the handler interceptor first. The handler :before should run and following that the path’s :before and :after, right?

Richie 2021-05-11T00:26:07.438400Z

I was motivated to post here because I see my understanding is wrong regarding how it works. I actually have the result I was trying to get…

Richie 2021-05-11T00:26:22.438600Z

Thanks for taking the time. brb

p-himik 2021-05-11T00:40:04.438800Z

That particular FAQ entry criticizes not hardcoding db paths but using db paths in your views. That's completely different. Two :before interceptors will run according to the order of the interceptors. Two :after interceptors will run in the reverse order. Any :before always runs before any :after. There was some nice pic in the documentation about it, IIRC. When in doubt, just read through re-frame source code (after you're done with the documentation, if you aren't that comfortable with reading code written by somebody else) - it's not that large, especially the relevant parts, and most of it is docstrings anyway. The most complex part is event queue IMO, and you don't need that part at all.

Richie 2021-05-11T01:35:12.439100Z

I did read through the source before coming up with my example. I think I understand it pretty well. In the first expression where the interceptor list has the handler followed by the path, I expect the handler :before to happen before the path :before. Then I would see the handler assoc :th under :db and not the path.

p-himik 2021-05-11T10:23:55.439400Z

Indeed that's what happens. But then :after of path puts in under that path.

bastilla 2021-05-11T12:25:16.439700Z

I think, I can assure neither :key nor the hiccup gets altered. But I had a fresh look at those sources you (@p-himik) mention. I think the problem is, I do de-reference the whole app-db later on. Via @rf-db/app-db. The app is highly dynamic and needs to read (not write) objects pointed to by other objects. And since I do not always have access to db via subscription I access app-db via @rf-db/app-db. And according to https://github.com/Day8/re-frame/issues/29, de-referencing (@) is problematic in terms of triggering unwanted re-rendering. (Check 8th post from top.) So (in my endless drive to go full retard) I thought about make my center subscription return the whole db, which then can be dynamically inspected for objects (pointed to by other objects). Like this:

(re-frame/reg-sub ::current-route
 (fn [db]
   (let [current-route (get-in db [:data :user-status :current-route])]
     [current-route db]))) ;; <--- Check last var
Question: Is this as foolish as it looks? Or could it be a way to randomly read the db without de-referencing (@) it later on?

p-himik 2021-05-11T12:50:55.440400Z

Oh, yeah, just dereferencing something will definitely lead to a re-rendering as well. Also, don't use app-db directly - not only it leads to issues such as you describe, it's also a private API. > I do not always have access to db via subscription What does this mean, exactly? What prevents you from just adding a new subscription - one that, as you put it, dynamically inspects app-db for whatever objects?

bastilla 2021-05-11T13:03:50.440600Z

I meant, as far as I understand the subscription signature, I cannot add an extra (random) param in order to query specific areas of app-db. That's where subscriptions seem to be limited: Just query pre-defined areas such as [:usr-data :images :logo :status], etc... But since my customers define their data themselves, there are areas in app-db that are blank to the application. (The app's knowledge ends at category level, e.g. [:data :objects].) And since I need to dynamically read objects outside subscriptions (which just points to pre-defined areas, AFAIK), I turned to directly reading @rf-db/app-db -- A no-no as you tell me. Everything could be solved, could I just return db from that initial subscription (see my snippet above). This certainly feels like overkill. But I don't know how else to solve that "dynamic/unknown areas" read demand.

p-himik 2021-05-11T13:16:07.440800Z

> I cannot add an extra (random) param in order to query specific areas of app-db Eh?

(reg-sub :my-sub
  (fn [db [_sub-id & path-in-db]]
    (get-in db path-in-db)))

p-himik 2021-05-11T13:16:32.441Z

That's exactly what that FAQ entry warns about, but it doesn't say you can't do it.

p-himik 2021-05-11T13:17:16.441200Z

If you know the path in advance - write it in a sub. If you don't know the path in advance - feed it to the sub. And you use the above sub as (subscribe [:my-sub :path :in :db]).

1🙌
bastilla 2021-05-11T13:27:30.441400Z

This is new information to me. (And I still need to deeply ponder what you're writing here.) You are refering https://day8.github.io/re-frame/FAQs/Inspecting-app-db/? At first glance I can't find that topic. But thanks! I have plenty of stuff to chew on now.

Fabim 2021-05-11T13:43:32.450600Z

Hey. Is there a best practice way to inject the js/document into a reg-sub using interceptors? My reframe subscription calculates the position of elements in a game board div in relation to each other. Using getElementById js/document and the .-offsetLeft to calculate css left and top would make the sub non pure. I could also do the positional math in the component directly.

p-himik 2021-05-11T14:07:07.450800Z

Interceptors are only for events, not subscriptions. No need to inject js/document anywhere because it's already a singleton. Unless you need to create mocks of documents. Even if you use js/document in a sub, the sub won't be recalculated because a document has nothing to do with the Reagent's reactive context. Don't use getElementById if you are the one controlling that component. Instead, use React refs. There are two reasonable ways to solve that: - Listen to some JS event that's fired when that position that you're interested in changes. If there are no such events, just do it on each requestAnimationFrame. In the JS event listener dispatch a re-frame event and write the position to the re-frame's app-db. In the relevant sub, just use that position - Don't use re-frame for that particular part of your app - just keep it confined to Reagent. But it's a trade-off

p-himik 2021-05-11T14:08:22.451Z

Oh, sorry - someone else linked that entry and I thought that was you because the topic is fundamentally the same. Here it is: https://day8.github.io/re-frame/correcting-a-wrong/#a-final-faq

p-himik 2021-05-11T14:09:19.451300Z

To expand on what I've written - both subs and events are parameterized. You decide what to put in those parameters, be it some values, specific path components in app-db, some callback functions, DOM elements (although don't do this).

Fabim 2021-05-11T16:08:22.451500Z

Ah thanks. Thought subs should be pure. My board cells don’t change. their offset is the reference point for tokens to move around. Would you still use react ref for it?

Richie 2021-05-11T17:22:14.451700Z

Ok, I think I have a better understanding now. I think what I was missing is that db-handler->interceptor writes the :coeffect :db into :effect :db. So, when I have interceptor chain where the handler precedes path then the path :before indexes nothing out of :coeffect :db and then the path :after grafts the :effect :db onto :effect :db.

Richie 2021-05-11T17:23:43.451900Z

This code produces the result I originally expected to see for that example.

(:effects
 (re-frame.interceptor/execute
  [:thing]
  [ (re-frame/->interceptor :id :add-thing
                            :before #(assoc-in % [:coeffects :db :th] 1)
                            :after identity)
   (re-frame.std-interceptors/path :p :a)
   (re-frame.std-interceptors/db-handler->interceptor identity)]))
;; {:db {:th 1, :p {:a nil}}}

paulbutcher 2021-05-11T17:24:10.452100Z

Thanks for taking the time to respond. As it happens, I tracked the problem down to an embarrassingly silly mistake on my part (blush).

Richie 2021-05-11T17:24:37.452400Z

Haha, no problem. I’m glad you fixed it.

Richie 2021-05-11T17:25:55.452600Z

Thanks for the help. I’m glad to have a better understanding. Now I’ll think about what is the problem I’m actually trying to solve.

1👍