This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # admin-announcements (6)
- # announcements (1)
- # beginners (1)
- # boot (104)
- # braid-chat (5)
- # cbus (1)
- # cider (2)
- # clojure (147)
- # clojure-japan (1)
- # clojure-poland (1)
- # clojure-russia (31)
- # clojurescript (16)
- # core-async (4)
- # css (2)
- # cursive (14)
- # datomic (40)
- # devcards (5)
- # dirac (100)
- # emacs (5)
- # funcool (1)
- # immutant (52)
- # juxt (4)
- # ldnclj (128)
- # lein-figwheel (12)
- # leiningen (26)
- # luminus (3)
- # mount (22)
- # off-topic (11)
- # om (144)
- # onyx (2)
- # parinfer (1)
- # proton (7)
- # re-frame (55)
- # reagent (16)
- # slack-help (5)
- # yada (1)
I'm just getting started with re-frame, and after looking at the example applications, I'm curious how to read the app-db atom directly. It looks like it's not necessary—both sample apps initialize it by merging some
initial-data map into the global
db, which is always the first argument to every handler. This is fine! And in fact, I can get to the app-db atom as
re-frame.db/app-db. I'm just not sure if that's what I should actually be doing.
@amacdougall: you really want to be getting app-db data through subscriptions, and changing it through handlers
Yep, that's definitely the approach I'm taking. If the debugging advice is to "take a snapshot of the app db so you can replay actions", I guess I'd write it to a known atom as a side effect of a handler at some point? And more generally, if I want to view the current app-db purely for debugging purposes,
re-frame.db/app-db is as good (or bad) a way as any.
@amacdougall: There's an FAQ entry on the debugging side of this: https://github.com/Day8/re-frame/wiki/FAQ#5-how-can-i-inspect-app-db I mention it for completeness, because it seems you have already mostly answered that question yourself.
There is also the not-documented-very-well
redo side of things, which causes snapshots to be taken. It may act as inspiration.
Sorry, I didn't grok your question correctly. In my mind the general pattern here is:
(rf/register-sub :item (fn [db _ [id]] (let [token (cause-database-query-to-happen :on-success #(dispatch [:write-to [:some :path])])] (make-reaction (fn  (get-in @db [:some :path])) :on-dispose #(do (cause-database-query-termination token) (rf/dispatch [:cleanup [:some :path]))))
In this pseudo code, I'm following this pattern:
1. We issue a query and organize that the async results are placed into
app-db at some location.
2. The subscription returns a reaction to that location
3. Via the
on-dispose you cleanup:
3.1 anything about the query itself (which might be a long lasting subscription in rethinkdb, or a one off.
3.2 any data now accumulated in
I think i got it. In my snippet database operations are inside
:items/unsub handlers so you could be implicit if there's would be a need to.
There are variation on all of this, of course, but you have nailed the salient points in your code.
No worries, that's totally understood. I just found this approach quite elegant and less verbose to track my server sub/unsub needs. Moreover to justify calling dispatchers from subscriptions i can say that data fetching is not actually an action but a workaround for a fact that your data is not in your client
app-db yet (just some words for me to sleep better).
Oh, yeah. I copied and pasted your code, when creating the pseudo code generalisation, and didn't notice the dynamic subscription
Moreover i thought that this approach can be applied for traditional data fetching. For example fetching can be called with every new subscription (with some debouncing) though that sounds much more doubtful.
Yeah, that's why in initial snippet i just call
:items/sub which itself handles data fetching and calling receiving event.
Yep, understand. My approach doesn't do that. Which is why I called out the subtle difference
BTW, this pattern has some very nice other subtle properties when dealing with databases like rethinkdb which provide the notion of change feeds.
You issue a query ... and then get many updates over time. So you are slowly accumulating state over time.
But equally, you need a way to "stop" the query. When the subscription is no longer needed
Sure. Unfortunately we don't have RethinkDB and we handle subscription mechanism in application logic, but that's not of client side interest
The other aspect is that you can "tag" queries/susbcriptions. And, then,when you issue a mutating query back to the database, you can tell all queries tagged "x" that they should be rerun, to produce new values.
:on-dispose stopping comes natural which i like. No need to make
:component-will-receive-props for each smart component.
For my task (though it looks quite general to me) there's also generic handler behaviour. There's a counter for each resource identifier (e.g.
:items/fetch-by-foo) and argument list (thanks to clojure equality here it's very simple), which is stored in
app-db or elsewhere. Counter is incremented on every
sub call and decremented on every
unsub call. On first increment (from 0 to 1) server subscription occurs and on last decrement (from 1 to 0) server unsubscription occurs. Shortly it's a simple reference counter.
Solution: 1. Don't use undo / redo 2. Wait for me to add a patch to re-frame to allow partial redo / undo (excluding certain paths, or only including certain paths)
There's one issue i found so far. Initially i stated that this approach allows easy resource tracking: you can unload resource once it has no corresponding subscriptions anymore. But in my case (don't know about the other once) resource usually have at least two overlapping subscriptions, e.g.
:some-item-parent/fetch-items which totally discards my idea.
Didn't think about undo. Maybe another solution is to store subscriptions in a separate atom? Ideally this atom can be defined with
defonce and doesn't need any special treatment as subscriptions will discard themselves but probably it brings some complexities as well.
No, there's no subscription for each children. Imagine some simple master detail. We wanna see a list of items (common info) and one specific item (detailed info). Thus we have to subscriptions, e.g.
:items/fetch. Subscribing each item individually would be painful anyway because you also have to track new/deleted items.
I think re-frame 0.7.0-alpha is supposed to work with reagent 0.6-alpha, but I haven't tried.
hi all, I’m trying to use react-bootstrap with adapt-react-class, and I’ve got a component that expects a function to the onClick prop. I’m passing #(dispatch …) as per the re-frame docs, but chrome complains that it’s getting a string rather than a function. The debugger shows that what it gets is, indeed, a string with a single hash: “#” Any ideas of what might be going on?
@mikethompson: Thanks for the advice! And more generally, thanks for being so active and helpful on this channel.
@tord I'd be interested to hear how you go with 0.6 of Reagent. Although I made the changes necessary to get re-frame working with that version, I haven't ever done much testing.
Although you'd probably be better posting to the reagent channel. I've got a feeling this isn't re-frame specific