This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-01-29
Channels
- # aatree (1)
- # admin-announcements (7)
- # announcements (3)
- # beginners (125)
- # boot (164)
- # braid-chat (8)
- # cider (26)
- # cljsrn (37)
- # clojars (3)
- # clojure (162)
- # clojure-argentina (1)
- # clojure-art (2)
- # clojure-berlin (5)
- # clojure-czech (3)
- # clojure-ireland (1)
- # clojure-miami (1)
- # clojure-norway (9)
- # clojure-russia (47)
- # clojurebridge (1)
- # clojurescript (151)
- # community-development (1)
- # conf-proposals (80)
- # core-async (15)
- # core-matrix (1)
- # cursive (66)
- # datomic (26)
- # emacs (17)
- # events (10)
- # funcool (59)
- # hoplon (43)
- # incanter (2)
- # jobs (10)
- # ldnclj (8)
- # lein-figwheel (18)
- # luminus (1)
- # off-topic (19)
- # om (144)
- # onyx (167)
- # overtone (9)
- # parinfer (12)
- # pedestal (1)
- # proton (158)
- # re-frame (139)
- # reagent (48)
- # test-check (19)
- # testing (43)
Case I’m trying to figure out the “right” way to handle is: search criteria changing in response to UI actions, every time the criteria changes I want to re-run the search via ajax so I’m looking for the right way to listen for changes to the criteria and kick that off
@pdlug: take a look at dynamic subscriptions
is most of the info on that page correct? because there is a big warning at the beginning of it
Is there a meaningful difference between these two components:
clojure
(defn c1 []
(let [s (re-frame/subscribe [:foobar])]
(fn [] [:div <@U06QXASV8>])))
(defn c2 []
[:div @(re-frame/subscribe [:foobar])])
It is my current understanding that with c2
what happens is when the :foobar
subscription changes, c2
re-renders, in the process subscribes again, which in turn calls the :foobar
subscription function again. In contrast with c1
the changed value of the :foobar
subscription is detected and used directly to re-render c1
without calling it a second time.
clj
(defn c3 []
(let [s (reaction (foobar @re-frame.db/app-db))]
(fn [] [:div <@U06QXASV8>])))
Now I think that c3
is equivalent to c1
. I don't yet see the advantage of using subscriptions.
Btw, I'm trying to figure this out because I have a performance problem. The turnaround time from hitting a key in an input field to react updating the value of the HTMLInputElement is over 100ms, which leads to lost keystrokes and a very jittery feel.
clojure
(def s (reaction (foobar @re-frame.db/app-db)))
(def c4 []
[:div <@U06QXASV8>])
Seems like the most straightforward way to me right now.@mbertheau: what handler middleware do you have ? (when i had similar perf problems it turned out to be schema-checking the app-db on every event which was the problem)
@mccraigmccraig: just debug and pure
c1
and c3
are the same. So much so that I really don't see that there's be a performance difference between them.
debug
can be slow
If it is diffing a big data structure
Remember that's what debug does. It does a complete diff of the before and after
Try removing it and seeing if performance suddenly improves
debug
should always be conditioned out in production
(if ^boolean js/goog.DEBUG debug)
@mikethompson: Thanks! How is js/goog.DEBUG set?
Automatically
If you are doing :advanced
compilations it will be false
If not, it will be true
Thank @mccraigmccraig, not me.
@mikethompson: Could you clarify the purpose of subscriptions vs. bare reactions as in c4
?
He pointed out the debug problem
@mccraigmccraig: Thank you
ha, yw
Take your glory where you can !!!
It is fickle
@mbertheau: if you aren't using :advanced
then you can also set goog-define
vars in the cljs compiler options
@mbertheau: c4 isn't often very good. You want those subscriptions/reactions to disappear when the component using them disappears. Hence use of form-2 versions.
regarding compile-time constants and goog-define
, see https://github.com/clojure/clojurescript/wiki/Compiler-Options#closure-defines
Anyone know why two subscribe calls with the same subscription don't share the same ratom?
I'd like to add that but I'm waiting on some changes to reagent
Does reaction
notice ratom derefs in a function that's called in the reaction
form? I.e. (def f [] (:foobar @db)) (def reactive-f (reaction (f)))
- is reactive-f updated if the db
ratom changes? Or do I have to write (def reactive-f (reaction (:foobar @db)))
?
@mbertheau: yes, any deref
of any ratom
anywhere is noticed during the computation wrapped by reaction
@mikethompson: Thanks!
hey people, where should I put my analytics events? trigger them from a middleware?
jaen: You know this semantic-ui dropdown example you gave me before? https://clojurians.slack.com/files/jaen/F0JKFP7T6/-.clj I’m having trouble adapting it for re-frame. Could you help me out a bit? I’m trying to keep each field in the form synced to a corresponding key in a foo-form-data map in the app-db, but I don’t know where to hook in the handler.
Theoretically you could call it inside onChange
, yes; I'm not sure why it doesn't work for you without seeing your code
I use something like this - https://gist.github.com/jaen/c59a3e0abcf0c6f6ade2 - because reagent/wrap
works only with values, not atoms/reactions.
(let [sub (rf/subscribe [:your-query])
value (wrap #(@sub) #(rf/dispatch [:update-sth] %))]
(fn []
[dropdown value choices]))
Would the advantage of this over just adding the dispatch to onChange be that it is a two way thing? both the dispatch and the subscription are synced?
Because I’m not sure if I just add an onChange dispatch, what would happen if the data is changed elsewhere.
In this case actually I think reagent wrapper would work as well:
(let [sub (rf/subscribe [:your-query])]
(fn []
[dropdown (r/wrap @sub #(rf/dispatch [:update-sth] %)) choices]))
ahhh yeah I see the difference. so the reagent one, were I to put it in the let binding, would only be bound once.
But if you put it in the inner function, it would be reactive depending on the sub anyway
What is the advantage? I think the advantage is consistency - that way the dropdown can always expect a reactive atom-like thing and you can just swap a normal atom or a cursor or such a wrapper
At least that's how it was when I tried that before and why I wrote my own wrapper that can be created in the outer function.
But at some point you will probably see that in some cases that way of creating a wrapper is not handy and then you can try mine; it's not too hard - it's basically just an atom-like thing that on deref
calls the first function, on reset!
- the other.
Guys, is anybody using dirac to have the nice handler/subs/views tracking in the browser console?
I was wondering if I can use both cljs-devtools
and dirac
interchangebly
So you can either have dirac
and cljs-devtools
, cljs-devtools
or none in your project and expect it to work.
oh ok, I am reading the README a bit more carefully sorry about that 😉
What dirac
adds on top of cljs-devtools
is basically a in-browser Clojurescript REPL and using custom formatters in the debugger as well, not only the console.
Well I use the repl in cider as I love to have my keybindings available 😉 but the debugger addition can be handy
Also always check your versions - different versions of dirac
and it's browser plugin can break it.
ok, a few disclaimers. 1. I haven’t really done much web dev in a while and very little in Clojure and 2. I’ve looked a Hoplon, Re-frame, Luminus, etc. and this might be a obvious/stupid question. I’m not sold on the idea that I want or need an SPA but I like the FRP approach. I find the idea of an app-state a bit unnerving but the README.md
talked me down off the ledge. So what I want is to do a multi-page app but have, say, page-db so that I can use FRP for all the AJAX-y things I would do in any webapp. Of course, I may change my mind later and move to an SPA. With that in mind, is it reasonable to combine, say, re-frame+luminus?
@actsasgeek: I don't see why not, but it depends how you want to deal with state when you are changing between one page and another in Luminus. I've thought about doing a combination of the 2, and then for each page have either the same re-frame app and dispatching specific mini-SPAs or building separate re-frame apps for each page.
Is that at all similar to what you're thinking of?
right, exactly. It’s all very hypothetical at this point, though.
Try building a bit of what you need it using just re-frame, or at least think about it - it's pretty nice and should give you a pretty good idea of how to do what you want. I basically went with re-frame and built an SPA just so I wouldn't have to deal with the mismatch and it worked out really well for what is primarily a forms rich CRUD app that I could have built using HTML for the majority of the functionality.
jaen: for this example,
(let [sub (rf/subscribe [:your-query])]
(fn []
[dropdown (r/wrap @sub #(rf/dispatch [:update-sth] %)) choices]))
If the subscription returns a vector, and I want to iterate [dropdown] over each thing in the vector, how should it be structured?it looks like [{:name foo :number foo :unit foo} {:name bar :number 12309 :unit foo}…]
And say I want a dropdown which would determine the values of :name, :number, :unit for each map
Hah, that's slightly complex. Any gist of the subscriptions and event handlers you have?
Ok, more simply, I wonder if it’s ok to
(let [sub (rf/subscribe [:your-query])]
(fn []
(for [item @sub]
[dropdown (r/wrap item #(rf/dispatch [:update-sth] %)) choices])))
, or should it I wrap the @sub?Well, it'll be a bit inefficient if you sub that way - update to any dropdown will re-render all.
Also another thing to consider is ^{:key "something-unique-for-a-row"}
. It is not strictly needed, but it makes React's reconciliation job easier and it will emit a warning if you don't use it.
Along the same lines, it should be possible to
(let [sub (rf/subscribe [:your-query])]
(fn []
[dropdown (r/wrap (@sub 0) #(rf/dispatch [:update-sth] %)) choices]))
as well?Though one thing about your event - how will you know which element of the list to update?
My :update dispatch function takes the list of keys to the value to be updated (like assoc-in)
Oh yeah speaking of which, is it correct that the % is outside of the dispatch vector?
Hah, I don't remember, I've never used re-frame library directly, even though I was highly inspired by the readme
It’s supposed to be the value to be dispatched right? I think the way I have my function it should be inside the vector. Thanks!
Yeah, my mistake - it seems re-frame expects you to call it like (rf/dispatch [:some.event/name param1 param2 ...])
@shaun-mahood: thanks for the suggestion. I guess my only thought was…I need a backend anyway and why not luminus, even if I don’t use everything.
@actsasgeek: Oh I think Luminus is a good choice. I ran into some issues with it months ago and ended up moving to a less framework-y solution for my backend, but I often refer to it to see what libraries I should bring in and I think it's a fantastic project. The only thing I was thinking was that it might be worth trying to just build an SPA and see if you really need the separation you were thinking of - I re-wrote my first re-frame app once or twice as I learned things, and if I had segregated things initially I would have missed out on some of the things I found and wouldn't have had as much fun.
yeah, that’s exactly where I am. I’m like…well, maybe I should create a re-frame project and then a luminus project to see what it requires and uses.
but the truth be told, I probably just need a vanilla ring/compojure project in the end.