This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-08-30
Channels
- # admin-announcements (1)
- # aws (32)
- # bangalore-clj (1)
- # beginners (2)
- # boot (137)
- # cider (2)
- # clara (1)
- # cljs-dev (39)
- # cljsrn (20)
- # clojure (268)
- # clojure-berlin (20)
- # clojure-canada (37)
- # clojure-dev (8)
- # clojure-gamedev (6)
- # clojure-norway (2)
- # clojure-russia (55)
- # clojure-spec (130)
- # clojure-uk (39)
- # clojurebridge (1)
- # clojurescript (102)
- # cursive (20)
- # datomic (231)
- # editors (5)
- # editors-rus (8)
- # events (5)
- # funcool (12)
- # hoplon (31)
- # instaparse (57)
- # jobs (9)
- # lein-figwheel (4)
- # off-topic (2)
- # om (8)
- # om-next (30)
- # onyx (241)
- # planck (6)
- # protorepl (4)
- # re-frame (115)
- # reagent (7)
- # rum (9)
- # schema (1)
- # test-check (9)
- # untangled (24)
- # yada (20)
looking awesome
we're thinking of adding analytics to certain events (e.g. navigation, item bought, item favorited, etc.)
essentially those would be side-effects triggered when the user takes a certain action
is that something that co-effects would help with?
@pesterhazy definitely. There is a builtin effect :dispatch or :dispatch-n so you can raise any other event when a event is handled. here you can find at the bottom the list of builtin effects: https://github.com/Day8/re-frame/blob/master/docs/Effects.md
@jmayaalv, that's a good start
I guess I'm wondering... we already have events, so maybe there's a way to "instrument" those events automatically
something like a middleware or, I guess, interceptor
@pesterhazy you could add an interceptor to the interceptor chain of relevant events you want to track
and the intereceptor could trigger another side-effect?
@pesterhazy the interceptor could take the event, put it under :track-event
and then you'd register an effect handler for :track-event
that would cause the tracking request to be sent off
i like it @martinklepsch i agree middleware is better fit for this
very interesting
is there an example of anything of this sort available?
I guess logging is kind of similar...
uhm, I've just found the first pattern here: https://github.com/Day8/re-frame/blob/master/docs/Subscribing-To-External-Data.md (never thought of it for some reason) and now I'm wondering: is it popular? Do Day8 use it? From the outside it seems like the second approach (make handlers do the fetching) is better supported, esp. after the addition of https://github.com/Day8/re-frame-http-fx
IMO the pattern outlined there conflates two things: 1) creating derived data (actual subscriptions) 2) creating a stateful thing that adds data to the sources impacting 1)
@s14: That document wasn't updated majorly for v0.8.0, so there may be some improvements that can be done now with the effectful handlers that aren't in there. If you haven't yet, it would be worth reading through all the docs on understanding event handlers and the "Talking to Servers" document. If you come up with something that works really well, though, let us know so we can add something to the docs about it.
I think it's safe to use either, but you might want to try them both for your use case to see which you prefer.
@shaun-mahood ah, now it makes more sense! Thanks. I'm working through the docs right now (even sent a PR with a minor fix :) )
@s14: Awesome, keep the PRs coming as you find problems, and if things are unclear feel free to ask here and we can hopefully add things to the docs to prevent future confusion as well.
a minor nitpick: it would be nice to have a "rationale" section in coeffects doc. I can see how useful it is for testing, but I'm curious if I miss other advantages of the "reified" approach
same for effects. There are jokes/notes like >That GET is a side effect, and side effecting functions are like a well salted paper cut. We try hard to avoid them. in a few places, but it would be awesome to add a link to that joke! :)
I'm sorry if this is a stupid question, but re: >Just to be clear: this does not mean you can run re-frame apps on the JVM (there's no React or Reagent available). I'm wondering if there are any unsurmountable obstacles to render re-frame on JVM similarly to Rum. Looks like it should be possible if one provides an explicit app-db, isn't it?
@si14 if I remember correctly there has been an attempt to do that, and the problem was that you need to "stop" the flow of events in order to produce the "current" view that is rendered by the server. Let me see if I can find a link
@richiardiandrea right, now when you've said it I remember I saw that too
> Currently we ship a simple heuristic: wait for 300ms of no events being triggered or 3s total, whichever happens first. When it looks like the page is rendered, a thunk is called back that should return the desired string to be sent to the client.
Rum doesn't manage state for you, so they are able to do this. The idea is to recreate React output in pure Clojure, here it is https://github.com/tonsky/rum/blob/gh-pages/src/rum/server_render.clj
I still need to try Rum for real, but re-frame
makes so much sense to me now that I can't find the time to switch 😉
You can have an event be done-rendering that prerender will watch for and cause it to be shipped. I never go around to implement it though.
the thing is maybe that I am not thinking about SEO yet
But it was planned and the code was going in that direction.
@pupeno maybe the idea above of using interceptors for this might be a winner
The dependency on NodeJS is unfortunate. I tried Nashorn but it doesn’t implement XMLHTTPRequest. I’m not sure how hard it is to implement it.
@pupeno @richiardiandrea it may possible to sidestep the issue completely and pre-bake app-db in server code, too
so no side effects, no events, no nothing, just one pass of app-db -> subscriptions -> views -> html
@si14 but I guess you need to define a "when" somehow right?
you still need to execute cljs to render the views.
@richiardiandrea sorry, I don't follow. What do you mean?
@pupeno why? Most of the view code (except js/
stuff, of course) can be executed on the server in Clojure
(lol no sorry, maybe I am not following)
Maybe I’m misremembering. I haven’t touched it in quite a while.
@si14 so your idea would be to run the entire event dispatching on the server?
@richiardiandrea why would you want events on the server if you control both client and server? Like on the client you would dispatch/use an effect to fetch data and then assoc
that data to the DB, right? But on the server you can just assoc
from your Postgres/Mongo/whatever to a map, encode into JSON/Transit/whatever and ship as a big blob to a client, which can in turn just synchronously reset!
it's app-db with the server-supplied one
I'm sorry if my ramblings are too obtuse, I'm just thinking out loud, not sure how it will play out (may find out in a few month, though)
@si14 yeah np, just asking your thoughts...I am basically doing that exactly when I bootstrap my app, I think the point here is not how to send the app-db
, but the views as well
like just take the state that you would consider initialized?
or loaded?
, fill it in on the server and ship along with some nice pseudo-React HTML
ah, the view part is solved by Rum, check this out https://github.com/tonsky/rum/blob/gh-pages/src/rum/server_render.clj
stateful JS components are a problem, though (will React populate them correctly right after the load if corresponding DOM is empty?)
Yes, the thing is, in my (maybe constrained) view. In re-frame each view is rendered on one of more triggering events (subscriptions), this is why I see you need in a way to "freeze" the flow of the events in order to produce the HTML-React stuff...
true that
(thinking...)
the problem is not the beginning I guess but when you want to pre-render a page while the "flow is going"
maybe it's a wrong mental model, but I thought that db is "frozen in time", so anything in the app happens "in ticks" (where "ticks" happens on external events), so it should be possible to find a database state that is "stable"
yes there is the concept of ticks, but I guess it is used internally in the state machine that dispatches events and it might be just for optimization purposes
the "stable" db is when you decide it to be (in case of @pupeno there is an ad hoc function)
yeah, I see where the difference is: @pupeno does it in a general case (take any re-frame app, put it into Node, done), while in the case that we are discussing you will need to know app-db structure
My library is designed to be generic. It doesn’t even depend on re-frame. You can use it without re-frame. I never tried it with Om though.
Yeah not easy problem to solve with re-frame
, maybe that is why there has been only one attempt so far
hey @shyambalu and @shaun-mahood I came up with what I think is a clever solution to the modal problem
then the top-level [modal-container]
view simply subscribes to :modal/state
where state looks like {:active bool :renderer-fn ‘some-namespace}
and the magic happens with a custom resolve
(https://clojuredocs.org/clojure.core/resolve) that works in cljs… so my modal-container looks like :
(defn modal-container []
(let [state (reframe/subscribe [:modal/state])]
(when (:visible? @state)
(r/with-let [_ (.addEventListener js/document "keydown" close-modal)]
[:div {:class s/container}
[(resolve-and-invoke (:active-renderer @state))]]
(finally
(.removeEventListener js/document "keydown" close-modal))))))
(note the vec surrounding resolve-and-invoke
, which enables implementers to return form-2 components)
although just as I’m writing this I realize it needs to be a bit smarter: checking if a vec is returned outright, or a fn is returned
it uses js/eval
to take a cljs symbol, convert it into a js-module string, then calls apply
A question about fetching data. In a navigation example like https://github.com/Day8/re-frame/blob/master/docs/Navigation.md, where would I arrange for extra data to be fetched from the server? Suppose panel2
requires an XHR request to fetch its data.
@pesterhazy you could dispatch an event when the component is mounted
or — more integrated — you could add hooks to your navigation handlers that will see "ah we're navigating to panel2
, so we'll need to fetch this data"
the first approach is fine but seems a bit against the reframean spirit
the second approach is probably the way to go
seems like a lot can be plugged into navigation handlers
- fetching data
- analytics events ("user navigated to panel2")
- authentication possibly?
basically hooks that should be triggered when you navigate to a certain url
so it should also be integrated with the routing solution ideally
not unlike what is described in the article (albeit about mobx): https://medium.com/@mweststrate/how-to-decouple-state-and-ui-a-k-a-you-dont-need-componentwillmount-cc90b787aa37#.9xrl3u8t4
@pesterhazy: can't answer fully right now, but I would take a look at the docs on talking to servers and think about adding effects to the navigation dispatch - so your dispatch would have an added effect with it to load or update existing data. https://github.com/yogthos/memory-hole shows one way to do it if you want to see a real app, but I'm not sure exactly how it is done there as I only looked at it very briefly.
@shaun-mahood cool I'll check that out. A full app to look at is very useful
this is the code: https://github.com/yogthos/memory-hole/blob/master/src/cljs/memory_hole/routes.cljs
@mikethompson https://github.com/Day8/re-frame/blame/master/docs/EffectfulHandlers.md#L348
@pesterhazy a data-based routing solution like bidi will be very useful in this context
(or at least something that takes a url and gives you a piece of data describing what it matched)
@pesterhazy: In case you haven't read it https://pupeno.com/2015/08/26/no-hashes-bidirectional-routing-in-re-frame-with-bidi-and-pushy/
an example with route params https://github.com/velveteer/celibidache/blob/master/src/app/routes.cljs
@velveteer: cool, that project is new to me. Mind adding it to the external resources on the re-frame wiki?
@shaun-mahood done 🙂
Awesome, thanks.