This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-08-08
Channels
- # admin-announcements (2)
- # beginners (35)
- # boot (353)
- # capetown (1)
- # cider (1)
- # cljs-dev (41)
- # cljsjs (3)
- # cljsrn (3)
- # clojure (118)
- # clojure-austin (12)
- # clojure-russia (17)
- # clojure-spec (21)
- # clojure-taiwan (1)
- # clojure-uk (91)
- # clojurescript (80)
- # clojurex (1)
- # cloverage (3)
- # datomic (66)
- # devcards (2)
- # events (2)
- # garden (6)
- # hoplon (54)
- # jobs-rus (1)
- # keechma (1)
- # lein-figwheel (4)
- # leiningen (3)
- # luminus (3)
- # off-topic (7)
- # om (4)
- # onyx (53)
- # other-languages (17)
- # proton (7)
- # protorepl (4)
- # re-frame (123)
- # reagent (1)
- # ring (6)
- # rum (2)
- # spacemacs (1)
- # specter (21)
- # testing (1)
- # untangled (1)
- # yada (42)
say you have two values in your app-db which both need to be set in order to do some action. These values can be set in any order. How do people deal with that type of situation?
@escherize: I'm not asking how to set two values in the db. I'm wondering how to trigger an action if and only if both values are not nil.
kind of like a business rule. if balance is negative AND user has enough overdraft protection allow transaction... that kind of thing.
I see. You can write a subscription for that or check in your event handler. Does it matter for anything besides that particular event?
(reg-event
:do-a-thing
(fn [db _]
(if (and (-> db :some :path)
(-> db :another :path :somewhere :heh))
(do-thing-to db)
db)))
?if you want to disable the view when not (and (-> db :some :path) (-> db :another :path :somewhere :heh))
, I'd reccomend a subscription
(def-sub :my-condition
(fn [db]
(and (-> db :some :path)
(-> db :another :path :somewhere :heh))))
;; this is the view:
(defn my-component []
(let some-condition (subscribe [:my-condition])
(fn []
[:div ...
(when @some-condition
[:input {:type :button
:on-click (fn [e]
(js/alert "i did it!"))}])])))
like i need to call it, and it will only (do-thing-to db) if conditions hold...but can't trigger by the setting of either of two locations?
It's a bit of a rough time in re-frame. that would be the same thing as register-handler
so, back to:
say you have two values in your app-db which both need to be set in order to do some action. These values can be set in any order. How do people deal with that type of situation?
what do you actually want to have happen?automatically on the setting of the variables...i want to react to the variables being set...
(register-handler
:maybe-call-backend
(fn [db _]
(if (and (-> db :some :path nil?)
(-> db :another :path :somewhere nil?))
(do (POST... )
(assoc :loading? db true))
db)))
When those two palces get updated, I think I would put a dispatch into maybe-call-backend
but i need to manually call that...i'm looking for something that gets triggered because the values are set...
to my mind, it may be difficult to keep track of what happens when. It may obfuscate the chain of causation a bit.
ok. currently I'm passing everything through a pub/sub core.async. Am planning to watch for variables, if i find them, check if the other is already set, if so do function...
but i find i have a lot of situations where a transition from one state to the next, depends on more than one variable to define the first state that is ready to transition to the next state so to speak.
@escherize: thanks for being a sounding board...now i must really go to sleep! lol 🙂
@fenton: I think this sounds like the classic cross-cutting issue that's solved best by middlware
Sounds like there are n
event handlers which might update m
pieces of state (m == n?)
. And decision d
is a function of those m
bits of state?
In which case, you'd normally wrap each of the n
handlers in a piece of middleware which looks at the m
pieces of state, and make the necessary d
The on-change
middleware interceptor is an example of this pattern
@mikethompson: fyi, I've found a bug in alpha10.
The path
interceptor doesn't allow for the possibility that it might be intercepting an FX handler which doesn't return a :db
effect. std_interceptors.cljc
line 171 does an unconditional assoc-effect
of full-db
into the context, when actually it's possible that your FX handler returned other effects but no change to the DB. The end result is that the :db
fx handler sees a :db
effect, but with a nil value, when it should see no :db
effect at all. This unfortunately causes your app-db to be wiped out, rather than left alone 😞
(reset! re-frame.db/app-db {:quux "don't delete me!"})
(reg-event-fx :foo [(path :quux)] (fn [db _] {:dispatch [:bar]}))
(reg-event-db :bar (fn [db _]
(println ":bar event db: " (pr-str db))
db))
(dispatch [:foo])
;; prints => ":bar event db: {:quux nil}"
Without the path
interceptor it does the right thing.Well, rather than me just complaining about it, this is probably more useful: https://github.com/Day8/re-frame/pull/189
Note that there is a crappy downside to this solution: if you do return {:db nil}
from an event handler with a path
interceptor, this will now consider that a no-op rather than wipe out that bit of the path. I've done it that way (a) because that's consistent with what the debug
middleware reports, and (b) because the interceptors
namespace doesn't expose an ability to differentiate between a {:db nil}
and a map with no :db
key at all.
But I actually think it should. Returning {:db nil}
from a handler with a path
interceptor seems like an eminently sensible way for a namespace to clean up after itself when the user's done with it.
Yeah, i see what you mean
@sam.roberton: Thanks!
@mikethompson: yes totally agree that this should be a middleware type thing. Is there a middleware hook of sorts? I want to hook in AFTER the event dispatch completes it's update of the app-db, since I'll be querying that. i cant use subscriptions because they are only UI focused and dont get run if not associated with some UI. What I'd like is a non-UI subscription. Perfect would be able to subscribe to multiple bits of data in the app-db.
maybe after
would be the ticket. It takes a function and the app-db
. Runs the function passing in the state of the app-db
after each and every dispatch occurs. Is that correct?
@johanatan: I just opened one of my existing apps using re-com and added ^{:key "my-key"}"
to a v-box
that has h-box
children, and it appears to work fine for me when I inspect the elements. Shows up with react-id of the form data-reactid=".b.3.$my-key.0"
on the parent and children, works for me with both re-com 0.6.1
and 0.8.3
so looks like nothings changed for that over the past year or so, at least for re-com
(all the other dependencies are about a year old).
@johanatan: I just looked also. I see the keys, but I needed to use the “React” plugin to Chrome. The regular inspector didn’t show them. (And I don't I see them in Safari). But they ARE needed. React throws an error and a warning if they aren’t there.
@shaun-mahood: did you add the :key to the v-box or to the h-box children?
@johanatan: I added it to the parent v-box and it showed up in both the parent and children when I inspected them.
@shaun-mahood: that isn't exactly useful here though-- the h-box children are the ones that are dynamic.
@wasser: hmm, interesting. i too see the :key values in the React plugin. but not on the original data-reactid in regular inspector
@wasser: the worrying thing here is that all other keys I'm using elsewhere affect the data-reactid
@johanatan: I attached the :key to each [h-box], inside the (for …).
@johanatan: Oh I misunderstood then - you want to add the :key to the children only then? I just tried that too and the result is that the child has data-reactid=".1.3.$my-key.$my-second-key"
attached.
@shaun-mahood: wow, it seems that you're seeing something different than myself and @wasser
I tried it on a single element though, so it may be something to do with how it works with a for
in there
@shaun-mahood: well, it does need to be a loop of some sort since the list itself is of dynamic length
Yeah you will definitely need a loop for what you want to do, but it looks like it works for me outside a loop. Going to see if I can find an existing loop to test in my code and if not I'll throw a new one in to check.
@shaun-mahood: awesome, thx!
[the other worrying thing here is that I see virtually no performance difference between the code w/ :key and that without]
It would be interesting to get some more context around the performance - I've not done anything using re-com with a ton of elements.
Well, I see it take up to a second or so when adding or removing items after the child list has grown to probably a hundred
[which is probably way beyond the actual use case I'm supporting here-- but I was stress testing when I found these limits 🙂 ]
@johanatan: and it seems to work fine, even without the react-id showing in the inspector (shrug)
@wasser: you wouldn't know if it is working or not unless you subsequently modified the list and saw performance improvements over not using :key
[so if you tie it up to on-click of a button which adds and removes items from the first 10% of the list and compare with and without :key, then we will know if it is working or not]
[also, you'd need to tweak how you are setting the IDs-- yours will always produce a range 0 -> length which would from React's perspective mean that things are only ever added or removed from the end (as React is using the ID as a proxy for identical?
)]
I can't seem to find any problems with data-reactid
on my project, added a couple of loops and everything still seems to apply and work as I would expect (same as above without the loop).
@johanatan: correct, I would typically base the :key off a unique property of the data element being rendered.
@johanatan: It might be worth starting a test app from the re-frame template (with +re-com) and see if you can get something working from there - if you get one something up on github that I can download I would be happy to try it on my machine in case there is something else weird going on.
@shaun-mahood: ok, i will do that. thx!
@johanatan: There might be something useful here https://github.com/Day8/re-frame/wiki/Creating%20Reagent%20Components - it's my go to source any time I have any problems like that
Well, this isn't really a "problem" per se-- it's just another detail that perhaps differs from my example to yours and @wasser 's
Except, hmm, maybe I really want my :key to be on the outer component here and not the h-box
@johanatan: I would guess it's likely an issue with your component rather than the v-box - what happens if you pull it out and just call v-box
directly with your existing code?
I find that the vast majority of bugs I run into are in my code, so much that when the underlying library has a bug it takes me forever to realize it because I assume I must be doing something wrong. In reagent particularly nearly all my errors are in how I define and call components.
[I tried putting the metadata before the (fn [] ...)
returned from the inner function as well as before the call to the inner-function like so: [^{:key "blah"} (the-func)]
]
Can you post the code that's not working? Also, try changing it to ^{:key "blah"} [the-func]
and see if that works - I've got that in my code and I believe it worked for me and carried the key through.
so the entire form is: (for [stuff collection] ^{:key "blah"} [(the-func stuff)]
[and that form is assigned to :children of the v-box]
No problem! I'm surprised that [(the-func stuff)]
and [the-func stuff]
didn't, as I've got that pattern with form-2 components all over the place working successfully. Along with the form-1-2-3 stuff, the other thing I need pretty frequent refreshers on in reagent is when to call using ( )
and when to call using [ ]
. Glad it's working for you - did performance improve at all?
No perceptible change in perf but I am doing one known sub-optimal thing in my own code so that is probably the reason.
Btw, suppose I have N of these vboxes with varying numbers of hbox children in each. Do all of the :keys across that entire structure need to be unique or is it ok if keys are only unique across one leaf branch?
oops, nm. I think I answered my own Q-- the parent key is represented as part of the child key so yes unique within one leaf branch is sufficient
@johanatan: Best place to read up on the [ ]
and ( )
differences is https://github.com/Day8/re-frame/wiki/Using-%5B%5D-instead-of-%28%29
@shaun-mahood: I'm familiar with all of that and follow it precisely
i.e., the-func
takes some arguments & returns a closure over those (and some of its own introduced) arguments. pretty sure if you try [the-func a b c d]
where a b c & d are said arguments, it will not work
@johanatan: Might be - I think it primarily depends on how you are defining the component and what it returns. Tough to get into the details of that part without seeing the code, I just know that everything I've done has been callable using [the-func a b c d]
without a problem and I don't think I've seen the pattern [(the-func a b c d)]
required anywhere else. Not sure that it actually causes any problems, though.
@johanatan: This is probably the point where our discussion gets less and less applicable to solving actual problems 🙂
Oooh, and the resulting output in the React plugin is nicer: now those components are named rather than anonymous "reagent-XX"
Awesome, glad it improved things for you. I think there is some potential for minor performance improvements there as well, but I doubt it would have any real impact (more of the "it's doing very very slightly less work" improvement than anything substantial).
Oh cool, you must have been running into one of the react-specific performance quirks. Glad it helped!