This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-23
Channels
- # beginners (81)
- # boot (1)
- # cider (1)
- # cljs-dev (15)
- # cljsrn (1)
- # clojure (27)
- # clojure-europe (9)
- # clojure-hamburg (2)
- # clojure-italy (6)
- # clojure-nl (6)
- # clojure-spec (10)
- # clojure-uk (33)
- # clojurescript (9)
- # clojurex (5)
- # cursive (14)
- # datomic (21)
- # devcards (2)
- # duct (72)
- # figwheel (1)
- # fulcro (6)
- # kaocha (3)
- # leiningen (5)
- # nrepl (10)
- # off-topic (65)
- # parinfer (12)
- # re-frame (68)
- # reagent (1)
- # reitit (14)
- # shadow-cljs (65)
- # spacemacs (6)
- # sql (4)
- # tools-deps (2)
- # yada (1)
@devurandom if I understand where you are trying to get to, this may be interesting ... https://github.com/Day8/re-frame/blob/master/docs/FAQs/LoadOnMount.md
WARNING: that FAQ entry does recommend not continuing in the direction you are leaning
Are there any guidelines on how one can break up bigger front-ends in re-frame? Right now I have done my own but I would like to see how others do it.
i break mine into feature-specific events, entity-based events, and (occasionally) feature-spanning events that coordinate
“change this state in feature foo” vs “update the global entity foo” vs “do this in foo, then after do this in bar and baz”
I don't want a events.cljs with 2k lines of code 🙂 (or more). Splitted it up already.
@jarvinenemil there's something in /doc
which talks about it:
https://github.com/Day8/re-frame/blob/master/docs/Basic-App-Structure.md
Thank you I will have a closer look @mikethompson ✌️
Perhaps also look at the example apps: https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md
Generally speaking you divide up by functional unit (which is normally page/panel)
One directory for each
Within that directory, all events views etc assoaicted with that functional unit: ie. events.cljs
,`view.cljs` subs.cljs
etc
perfect, I will do some refactoring
If I have a sub for coll
(for the list-all-in-coll page) and one for (get coll id)
(for the show-item-details page), I'm doing it roughly as intended, right?
@mikethompson Thanks for the links!
@mikethompson Assuming I have a (reg-sub ::my-coll)
, would it indeed be stupid to have a:
(reg-event-fx
::re-frame/sub-realised
; Triggered when the subscription is actually realised, i.e. the first time someone subscribes
(fn [cofx [_ sub]]
(if-let [handler (get sub-realisation-handlers sub)]
(handler cofx sub))))
(def sub-realisation-handlers
{::my-coll my-coll-sub-realisation-handler})
(defn my-coll-sub-realisation-handler [cofx sub]
"Fill my-coll with data via a re-graph subscription"
{::re-graph/subscribe ...})
That way my pages would just care about their data input, i.e. their subscriptions, instead of having to care about triggering the process that makes this data arrive in the subscription.
And it's still events causing side-effects. With the small change that now re-frame's realisation of the subscription (previously an implementation detail) also dispatches events.
I use reg-sub-raw to achieve that @devurandom
@oliy You (dispatch [::my-coll-queried])
from within the ::my-coll
raw subscription? And then the event handler checks whether the re-graph subscription already exists and creates it if not?
Yes, sort of. It uses the lifecycle of the subscription to subscribe and unsubscribe in re-graph
On the topic of Eric's post on react vs re-frame: "That said, you don't have to do it using Events and the Database at all. You can simply create a Reagent Atom that always has the current value of document.body.scrollTop." << Is that actually re-framy? Having data outside of :db that my view uses?
I sometimes do that for very local state that I don't care about reproducing e.g. does a text input have focus or not
@oliy That would be awesome!
@devurandom here you go: https://gist.github.com/oliyh/7a99b986059832951f28e6a26827dbc1
i hope it makes sense - a pattern for a subscription that manages its own data source, in both re-graph and martian flavours
that way when anyone needs some data, you just subscribe to the data source, you don't have to care where it comes from or how to initialise it or how to clean it up afterwards
(re-graph/reg-sub ::raw-things "{ things { id } }")
, which would automatically create the re-frame/reg-sub-raw
and the re-frame/reg-event-db
from your paste.
There are many different use cases, it would only make it easier for one, but maybe more confusing for others. For example I sometimes use a subscription just to get one message, which might take time like
(re-frame/reg-event-fx
::on-transfer
(fn [cofx [_ {:keys [data errors] :as payload}]]
{:db (update (:db cofx) :transfer-data #(merge % (:money_transfer data)))
:dispatch [::re-graph/unsubscribe (keyword (str "transfer-" (:uuid (:money_transfer data))))]}))
even in my own codebases i tend not to have a generic version of that, because each one tends to be slightly different
It's a bit of cqrs-like demo, I pass the command to transfer some ammount to the graphQl server, it then gets processed by other applications with kafka messages, and eventually (but in practice really fast) either a failed or succeed messages will be read by the graphQl server, witch, because of the subscription, will pass it to the client.
(the arguments vector is important as that is part of what governs re-frame's deduplication)
Would be really great if I could build something like that for actual production use, this was kind of a poc, on my own initiative, but could not convince the decision makers.
Is there a way to "queue" a subscription? My problem is that initially when the app starts I don't know the re-graph configuration. It arrives later and then a ::re-graph/init
is dispatched, but in the meantime I might have tried to issue some subscriptions already, which would fail, because there was no re-graph config yet.
@oliy Do you have a http://cljdoc.org page for re-graph?
Try it, it's awesome. You can also have prose text, like re-frame's documentation, alongside the API docs. Very useful.
FWIW cljdoc builds docs automatically so you can just look up re-graph docs via the search on the home page... here's the re-graph docs: https://cljdoc.org/d/re-graph
If you want I can open a PR adding a badge.
It's described here just in case you're curious: https://github.com/cljdoc/cljdoc/blob/master/doc/userguide/for-library-authors.adoc#basic-setup
there's no current way to queue a subscription because you need to init re-graph first so it knows where and how to queue things
but you're the second person to ask that recently (unless you're the one who raised it on github the other day) so it seems like it could be a required feature
in my apps authing the user, initing re-graph etc are all things that are done before the views are mounted, and it's the views that subscribe to the subs that want to fetch data
if you want you can raise an issue on github with an example of how you would want to use it
I would add an optional argument to ::re-graph/subscribe
: an options map that contains a key :queue?
, and then add the following to the handler function, before :else
:
(:queue? options)
{:db (update-in db [:subscription-queue] conj [subscription-id query variables callback-event])}
And in the ::re-graph/init
handler check the :subscription-queue
and execute all those subscriptions after initialising the data structures.
I'm trying to understand ::re-graph/subscribe
: When the websocket is not ready, but it exists, you immediately queue the result event without actually subscribing to anything or fetching any data?
Maybe we are using a wrong approach, would be interesting to hear your opinion on this: Because in the frontend CLJS code we do not know where the GraphQL backend will be, we load a config file from the frontend web server (we can make that point to the correct backend server for every deployment of our generated-JS frontend code). Hence we cannot ::re-graph/init
right after the application loads in the browser, because we first have to wait for the config, and only as a result of the config arriving we will initialise re-graph. Before my idea of doing the re-graph subscriptions automatically from re-frame subscriptions, we would also dispatch several ::re-graph/subscribe
right after dispatching ::re-graph/init
.
We could workaround this by ourselves if ::re-graph/subscribe
had an on-failure event in addition to the on-success event (`callback-event` in the ::re-graph/subscribe
code). This event would have to be dispatched in the :else
branch of ::re-graph/subscribe
.
i would organise it like this
(defn app-init []
(go (let [ws-endpoint (<! (fetch-config))]
(re-graph/init ws-endpoint)
(reagent/mount-component [root-component]))))
this will block your app from rendering until it knows where the backend is, of course, but for the apps i do that is ok
We use honeybadger also for Clojurescript, and I noticed that for some reason all re-frame errors triggered by something like
(rf/dispatch [::not-found])
don't get logged
re-frame: no :event handler registered for: :event-handler-not-there
(anonymous) @ core.cljs:3884
(anonymous) @ core.cljs:3879
(anonymous) @ core.cljs:3873
(anonymous) @ core.cljs:3867
(anonymous) @ core.cljs:3861
(anonymous) @ core.cljs:3896
cljs$core$apply @ core.cljs:3887
(anonymous) @ loggers.cljc?rel=1541758287855:38
re_frame$loggers$console @ loggers.cljc?rel=1541758287855:35
(anonymous) @ registrar.cljc?rel=1541758288685:31
re_frame$registrar$get_handler @ registrar.cljc?rel=1541758288685:18
re_frame$events$handle @ events.cljc?rel=1541758289590:57
(anonymous) @ router.cljc?rel=1541758289832:179
re_frame$router$_process_1st_event_in_queue @ router.cljc?rel=1541758289832:84
(anonymous) @ router.cljc?rel=1541758289832:198
re_frame$router$_run_queue @ router.cljc?rel=1541758289832:86
(anonymous) @ router.cljc?rel=1541758289832:146
(anonymous) @ router.cljc?rel=1541758289832:169
re_frame$router$_fsm_trigger @ router.cljc?rel=1541758289832:80
(anonymous) @ router.cljc?rel=1541758289832:187
channel.port1.onmessage @ nexttick.js:211
we hook to window.onerror
if I understand correctly
any idea how to catch these errors as well?
@andrea.crotti See the FAQs #7
https://github.com/Day8/re-frame/blob/master/docs/FAQs
for a description of how to hook that re-frame: no :event handler registered for: :event-handler-not-there
error