Fork me on GitHub
#reagent
<
2016-09-03
>
mikethompson05:09:53

@johanatan Can you give a bit more info ? Do you mean you want to do this:

(defn my-component
   []
   ^{:key "blah"}(some-other))

mikethompson05:09:47

If so, remember that ^{:key "blah"} will only work on a literal

mikethompson05:09:22

So this works:

^{:key "blah"}[]
But this does not:
^{:key "blah"}(identity [])

mikethompson05:09:04

For the second one, you have to instead use with-meta

johanatan05:09:34

@mikethompson No, I literally wanted to do it on a (fn [] ...)

johanatan05:09:38

i.e., a Form-2 component

johanatan05:09:28

I also did try with-meta when I was messing around with this but it didn't work.

johanatan05:09:39

I ended up converting my Form-2 components into Form-1 components

johanatan05:09:58

As I realized that I didn't really need to close over any local state anyway

johanatan05:09:00

And it could be recomputed with impunity

johanatan05:09:21

So... imagine this:

(defn timer-component []
  (let [seconds-elapsed (reagent/atom 0)]     ;; setup, and local state
    ^{:key "want to put key here"}
    (fn []        ;; inner, render function is returned
      (js/setTimeout #(swap! seconds-elapsed inc) 1000)
      [:div "Seconds Elapsed: " @seconds-elapsed])))

johanatan05:09:51

I also tried:

(defn timer-component []
  (let [seconds-elapsed (reagent/atom 0)]     ;; setup, and local state
    (with-meta
      (fn []        ;; inner, render function is returned
        (js/setTimeout #(swap! seconds-elapsed inc) 1000)
        [:div "Seconds Elapsed: " @seconds-elapsed])
      {:key "key here"})))    
and that did not result in a 'key' being shown in the React dev tools in Chrome

mikethompson06:09:09

@johanatan think about it this way. Reagent allows you to return a hiccup formatted data structure (nested vectors and maps). And parts of that data structure can have meta data which indicates keys.

mikethompson06:09:52

You seem to be trying to do something else 🙂

mikethompson06:09:34

It is like you are trying to add key meta data to the functions which return the hiccup, rather than the hiccup itself

johanatan07:09:05

No, the fn I tried to add it to is a return value. It is not directly invoked by any of my code but rather by the runtime/framework code.

johanatan07:09:12

Reagent also allows you to "return this type of fn-defined component". It is known as a Form-2 component (per the Reagent docs).

johanatan07:09:57

You can easily verify for yourself what I'm telling you: construct a page with at least one Form-2 component and notice that you see a "ReagentXX" element in the Chrome React dev tools element hierarchy corresponding to each Form-2 component on your page. Notice also that upon each render these Form-2 components' element types get the XX bumped. Notice also how that is a killer on performance as React considers unique element types to be unique in substance as well as type (and thus not identical and thus not eligible for its perf-enhancing goodness).

johanatan07:09:07

I would like to change that (hence the desire to add :key metadata to the closure).

mikethompson14:09:27

@johanatan I assure you I understand Form-2 components reasonably well. I named them when I wrote the documentation 🙂 I'm confused by what you are saying. I fired up the todomvc example supplied with re-frame. It has a component called task-list which is Form-2. I look at it in Chrome React devtools and I don't see a ReagentXX element, as you suggest I might. . And I see no key on it. So I'm stuck as to how to interpret your question.

johanatan17:09:48

@mikethompson the fact that you see no key on it is expected and what i would like to change so not sure why you mentioned that. i'm also not sure why you are having trouble understanding my words as I think I've been very clear and precise. what part of my question do you not understand? Perhaps one more detail that is different between our codes: can you try having the timer-component above as a child in a v-box like so: [re-com/v-box :children [(timer-component)]. Then I think you should see the "reagentXX" as expected in the React devtools hierarchy.

johanatan17:09:19

Are you also saying that under no circumstance ever have you seen the "reagentXX" components appear in your React devtools hierarchy? I would imagine that at least one of the Reagent devs would know the source of/trigger for the creation of this [problematic] type of component but if none of them chime in anytime soon, then I will dig into the source code and see for myself.

mikethompson17:09:38

@johanatan When you use a Form2 component, you absolutely not should be calling it in the hiccup like this [(timer-component)] you should instead be [timer-component]

johanatan18:09:15

@mikethompson yes, I understand/know that but when this Form-2 component has another Form-2 component as a child, then the child does not get updated properly when both are specified like [component]. changing the outer one to [(component)] fixes my "does not update when input cursors" change issue on the child hence why I did that.

mikethompson18:09:24

When you use the [(timer-component)] you will indeed be recreating the component each time.

mikethompson18:09:14

@johanatan > when this Form-2 component has another Form-2 component as a child, then the child does not get updated properly when both are specified like [component] This should work fine. Done it a 1000 times.

johanatan18:09:48

Hmm, then there must be other confounding factors

mikethompson18:09:34

I think you need to great a minimal repo showing an example of the problem you are seeing. Then we can probably help more.

johanatan18:09:52

Ok, I'll try that. Thanks

johanatan18:09:13

Do you know if "trace react updates" can be trusted? I'm sort of doubting some of its output and wonder if this: https://github.com/facebook/react-devtools/issues/337 is a factor?

johanatan18:09:25

i.e., my code per your "when do components update" should not be updating many of its components as much as the "trace react updates" from devtools is indicating. Not sure if those are really being updated or if I am suffering from the fact that react-devtools is not honoring shouldComponentUpdate return values (which reagent may be giving it).

mikethompson18:09:21

If you are unsure, put a println in the render part of any component.

mikethompson18:09:15

(defn my-component 
    [] 
    ....                        ;;  don't put a println out here because this isn't the renderer
    (fn [] 
       (println  "rendering my-component")
       [:div "hello"]))

johanatan18:09:20

ahh, good call. thx!

johanatan18:09:57

Hmm, well I guess part of the confusion here is that I know certain render functions (which are ancestors of the input being typed into) must be running (as the input being typed into is on a leaf node)

johanatan18:09:23

But all of the elements returned to React higher up in the tree should be identical from a DOM perspective to the previous iteration

mikethompson18:09:24

(defn my-component 
    [] 
    (println "my component setup - should only be called once")
    ....                        
    (fn [] 
       (println  "rendering my-component")
       [:div "hello"]))

johanatan18:09:04

And IIUC "trace react updates" should not be highlighting structurally identical DOM elements from one render to the next

johanatan18:09:34

e.g., one of the elements in question is a Material UI "toggle" element which should have identical inputs from the previous iteration

johanatan18:09:55

Yet "trace react updates" is highlighting it and many of its siblings/cousins on the way to the leaf input which is actually being typed into

johanatan18:09:09

[and which is the only thing actually changing on the page]

johanatan18:09:18

So I guess I'm really asking: does "trace react updates" actually highlight DOM elements that have changed? or elements which were generated by render functions which ran (but may or may not have actually changed)?

johanatan18:09:22

It seems empirically to me that it is the latter and that it probably isn't a big deal that many of these are re-drawing (as there isn't really any better/other way to structure this to prevent it).

mikethompson18:09:17

Not sure about that extension ... i don't use it

mikethompson18:09:41

Now wait. This is the reagent channel, not the re-frame channel. So you may not be using re-frame.

johanatan19:09:48

@mikethompson I actually am using re-frame. But I'm finding that reagent/cursor is typically all I need for event sources (rather than a full-blown subscription and handler).

johanatan19:09:32

So the renders in question are all tied to cursor rather than subscription and so I don't think that event-based debugging will help.