This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-06-12
Channels
- # beginners (81)
- # boot (29)
- # cider (7)
- # cljs-dev (147)
- # cljsrn (5)
- # clojure (121)
- # clojure-austin (4)
- # clojure-conj (4)
- # clojure-italy (9)
- # clojure-russia (20)
- # clojure-sg (1)
- # clojure-spec (25)
- # clojure-uk (34)
- # clojurescript (137)
- # cryogen (2)
- # cursive (1)
- # data-science (1)
- # datomic (29)
- # events (9)
- # figwheel (1)
- # hoplon (14)
- # jobs (2)
- # luminus (2)
- # off-topic (7)
- # om (36)
- # onyx (6)
- # parinfer (14)
- # re-frame (13)
- # reagent (74)
- # specter (2)
- # test-check (1)
- # untangled (43)
- # vim (14)
- # yada (36)
I'm sure this has been covered many times, but I can't find it atm. Do form-2 components need to have their arguments duplicated in the returned anonymous function?
the reason is that, if you don't do that, the render fn will only see the initial props, even if the component receives new props
it will appear to work initially, but you'll notice that the component doesn't update under certain circumstanes
I have the following code: https://gist.github.com/borkdude/177148ef9d57cb144e26bf2f16e4c7da
The problem is that when the loading?
value changes, the child component report-iframe
gets mounted a second time. Why?
my advice is not to specify the props in the outer fn at all - you should usually use the props in the inner fn only
@pesterhazy oh, I didn't know that was valid to omit them in the outer function. Cool, thanks
because clojurescript is javascript, you can call a fn with the "wrong" number of args
note that the report-iframe
component is not inside the when, so I didn’t expect this value to affect the mounting of the component
@borkdude it's easier to help if you can reproduce the problem in a klipse
@pesterhazy Got it: http://app.klipse.tech/?container&cljs_in.gist=borkdude/fd61bc806e6c3096551509d22c6a68de
Note that when I call report-iframe directly (without the intermediate report component) it works without remounting
@borkdude so what's the behavior you expect, and what's the behavior you're seeing?
hm ok
@borkdude why do you want to avoid remounting the component?
I load some components in the iframe which can take a while to finish. When they are finished, I call the parent frame which then should display the iframe
I do this via the loading? value, but when it’s remounted it defeats the purpose, because it does all the work a second time
so that's why
check this:
(defn report [loading?]
[:div
[:div
(when loading?
[:div "Loading..."])]
[report-iframe loading?]])
this works
the problem is that in your original, the structure of your element hierarchy changes, from [:div [:div ...] [report-iframe ...]]
to [:div [report-iframe ...]]
, and vice versa
react can't figure out that you added/removed an element before your componenet
so it does the simpleminded thing of remounting all children
becausre tree diffing as a general task is very complex (quadratic? or worse), react uses heuristics to diff prev-tree and curr-tree
you kind of have to structure your dom in such a way that react can see the commonalities
So now it does what I want: http://app.klipse.tech/?container&cljs_in.gist=borkdude/fd61bc806e6c3096551509d22c6a68de
kudos to @viebel for klipse, which makes it so much easier to figure this stuff out together
It’s much simpler to debug tough issues when you can see the code in action @borkdude @pesterhazy
This could probably also be solved by adding React keys manually:
(defn report [loading?]
[:div
(when loading?
[:div {:key "loading"} "Loading..."])
^{:key "report"} [report-iframe loading?]])
This way React can see that "loading" element is removed/added, and "report" is always presentWithout these manual keys, the index of children is used as key, so if loading is shown it will be element "0" and report "1", if loading is not shown report is "0"
Solution without additional wrapper elements is usually easier for styling
Now that I think about this, I have probably written lots of code with similar (when loading? ..)
and (when error ...)
But I guess this won't be a problem with stateless Reagent components
Is this not a problem with Reagent?
Remounting a component is usually so fast it doesn't matter, iframe is a special case
Animated components would be another case where it matters when component is added/removed
True but just randomly using keys for children seems dangerous
What this does is to essentially silence react's warning message
Hmm, no?
Setting keys manually is fine
It allows the React diffing to detect which elements are added/removed
I know that
@juhoteperi, my point is that by default React issues a warning if you don't set keys manually. If I understand Reagent's behavior correctly, it overrides this warning by issuing automatically assigned keys to children.
or is that not true?
React automatically uses index of the children for key, not Reagent
do you have a link to back that up?
not saying it's not true, but I'd love to read up on it
Or maybe more specifically, React diff algorithm uses the index of children if key is not provided
it's actually explained pretty well there
It says >>> It is important to remember that the reconciliation algorithm is an implementation detail. React could rerender the whole app on every action; the end result would be the same.
that's kind of not true... sometimes you have to rely on the fact that components persist across changes, i.e. when those components have some rich state
e.g. you don't want to just re-mount a <video>
tag ... you would lose the buffer, playback position etc
so there are time where making sure that a component stays moment is more than just a performance optimization
but yeah that supports your interpretation I think
https://facebook.github.io/react/docs/conditional-rendering.html#preventing-component-from-rendering This is pretty much the same, but the solution in this example is to always include the component in tree but render empty content for it
Can't find docs about how keys/diffing works for static children. It was more obvious before when React keys where present in DOM.
This works also:
(defn loading [loading?]
(if loading?
[:div "Loading..."]))
(defn report [loading?]
[:div
[loading loading?]
[report-iframe loading?]])
moving the loading indicator after the iframe would also work