Fork me on GitHub
#re-frame
<
2023-02-21
>
Emanuel Rylke08:02:33

To fetch entities on-demand from the server I'm considering something like this:

(rf/reg-sub :entity
            (fn [db [_ id]]
              (rf/dispatch [:ensure-entity-fetched id])
              (get-in db [:entities id])))

(rf/reg-event-fx :ensure-entity-fetched
                 (fn [{:keys [db]} [_ id]]
                   (when-not (get-in db [:entity-fetched id])
                     {:db (assoc-in db [:entity-fetched id] true)
                      :fx [;; do the fetching
                           ]})))
As I suspect that doing a dispatch inside a subscription isn't the most idiomatic re-frame I was wondering if anyone might see any issues I might run into with this approach?

p-himik08:02:02

• Subscriptions are cached, which might or might not be a problem in your case, and you won't know when it becomes a problem • Your sub will re-dispatch every single time app-db changes • Since dispatch effects are queued, you're likely to fetch the same entity multiple times IMO it's much better to figure out what data you need in advance and request it explicitly.

hifumi12308:02:23

dispatch inside a sub is akin to just using side effects directly in the sub; it may work, but it’ll also be very brittle and hard to test. It’s also unclear to me how that event is being dispatched on every subscription, because two components may be subscribing to the exact same id , and assuming the app-db stays equal, then I would suspect the values are simply cached

hifumi12308:02:11

if I had to receive things in real time from a backend server, I’d look into wrapping Server Side Events or Websockets into re-frame (I already do this in one of my re-frame apps for getting live messages from a server)

Emanuel Rylke08:02:11

To clarify, I do want the entity to be only fetched once, so the subscription being cached is not an issue. > Since dispatch effects are queued, you're likely to fetch the same entity multiple times I assumed changes to the DB would be applied before the next event is processed. So this is something I would have to verify.

lassemaatta08:02:47

(not saying you should do this but) I think you could perhaps leverage reg-sub-raw for this, as was once referred to in the docs (https://day8.github.io/re-frame/Subscribing-To-External-Data/#some-code, do note the disclaimers at the top)

👀 4
p-himik08:02:13

> I assumed changes to the DB would be applied before the next event is processed Ah, I didn't read the :db effect right. You're correct.

rolt13:02:18

we had duplicate queries with this pattern in some rare cases, i don't remember why. And we fixed it by manually de-duping: ";; do the fetching" would register the query in a queue, and the queue processor would dedupe before fetching (or we dedupe when registering, cant remember). Also don't under estimate the subscription cache problem. We didn't have this problem because our entities would be automatically updated when changed (which bring other problems...) but you should not rely on the components lifecycle to "refresh" your queries

Doug Kirk14:02:27

This coding pattern will work since you have a guard, but usually the ;; do the fetching is asynchronous, so you'll want another fx-handler to handle the result of fetching. That is, updating the DB with the value. Which will re-trigger your render function and re-invoke the sub, returning the value recently fetched. Take a look at the readme for https://github.com/day8/re-frame-http-fx. You can still roll your own, but the pattern is the same. More commonly there is some UI event that will trigger the dispatch to [:ensure-entity-fetched] separate of the subscription.

👍 2
rads14:02:45

Has anyone attempted to implement a Re-frame interface over a hook-based query fetching/caching lib like react-query ? The goal would be to leverage the features from react-query (e.g. automatic re-fetching on focus) without having to use hook interop in a Reagent/Re-frame app. I think the rf/subscribe call would have to do the useQuery call internally, but maybe you could make this work with reg-sub-raw . This is a project I've considered taking on myself but I wanted to see if anyone else had explored this area

rads03:02:36

Here's an initial proof-of-concept: https://github.com/rads/rf-query

🎉 6
👍 2
hifumi12303:02:47

Have you considered using a higher order function component to expose the hooks? Not sure if this is possible but it'd be a nice way for the user to avoid having to make their own function components

rads04:02:09

That's a good suggestion. It means we could call rf/subscribe directly instead of wrapping it

rads05:02:39

@U0479UCF48H: I just pushed up another version with the higher-order component. I think this looks better than what I had before

👍 2