Fork me on GitHub
#reagent
<
2021-12-03
>
drewverlee02:12:50

can you provide the react child unique key in the map to the 2nd arg of the hiccup vector or does it need to be the for loop with meta data?

drewverlee02:12:29

(defn lister [items]
  [:ul
   (for [item items]
     ^{:key item} [:li "Item " item])])
or can it be
(map (fn [item] [:li {:key ...

juhoteperi16:12:47

For built-in elements, like :li, both are fine. I think pretty much all Reagent versions support this. (Reagent doesn't need to do anything here, if second vector element is a map, it is used as properties to the React element, and React will see the key.) For Reagent components (where the first vector element is a function) only the metadata works. (Here Reagent takes the key from metadata, and passes it to React element which refers to the component.)

drewverlee02:12:06

err, maybe i'm on a older version of reagent to where only the first is allowed.

NoahTheDuke16:12:38

is it possible to trace why a given component is rerendering?

p-himik16:12:58

If it's a form-1 or form-2 component, either the resulting Hiccup is different or its :key, if set, is different. Usually it's rather easy to trace it given that information. But also React Developer Tools extension allows to record the reason for why components are re-rendered during profiling. Not sure how useful it is though - I've never used it myself.

juhoteperi16:12:51

Component render is called if either parent component was re-rendered, or component state (ratoms, hooks) is updated.

juhoteperi16:12:03

You could use console.log or such to check if the parent component is re-rendered.

juhoteperi16:12:19

And yeah, React developer tools also. If the parent isn't being re-rendered, and only this component is rendered, you need to go through ratoms derefs etc.

NoahTheDuke16:12:00

it’s a form 1 with r/with-let: (r/with-let [run-info (r/track #(get-in @runs [@chosen-format side]))] , which i suspect is the source of the issue. runs and format are top-level ratoms that are reset when the page first loads

NoahTheDuke16:12:36

is r/track checking for updates on a timer of some kind?

juhoteperi16:12:56

No, ratoms keep track of their uses, and updating a ratom triggers update on dependent ratoms.

juhoteperi16:12:27

e.g. runs ratom knows it is being used by this track (which is also a ratom) and when ever runs is updated, it tells this track to update also

juhoteperi16:12:01

Is the component being rendered repeatedly? Are you also updating one of the input ratoms in the render body?

p-himik16:12:38

@U061V0GG2 So does a re-render of a child component happen if a parent component is re-rendered (e.g. because it derefs some ratom that was changed) but that child component does not depend on that state and is still the same Hiccup as before?

juhoteperi16:12:13

"same Hiccup" doesn't matter at all, Reagent doesn't keep track of the render fn return value

p-himik16:12:25

Well, same Hiccup leads to same exact tree of React elements - that's my reasoning.

juhoteperi16:12:40

React itself will compare rendered React element tree to Shadow DOM and use that for the real DOM operations

juhoteperi16:12:44

But this is at different level

p-himik16:12:21

Alright. So if I understand your initial statement correctly, in the code below the child function should be called each time I press the button? Because each button press leads to parent being re-rendered.

(def state (r/atom 0))

(defn child []
  [:span "child"])

(defn app []
  [:div
   "parent " @state
   [:button {:on-click #(swap! state inc)}
    "Change state"]
   [child]])

juhoteperi16:12:43

Reagent component render fns are always called if the component is rendered, and every time a component render is called, all its children will be rendered also. This should be documented somewhere in React docs.

p-himik16:12:10

But that's not the case. I just experimented - child is called only once.

p-himik16:12:17

The props of the child component have not been changed - why would it be re-rendered by React?

juhoteperi16:12:39

Yeah, you are correct, component is only re-rendered if the props change or the state (ratoms etc.) change. Maybe I've been writing too many components which are passing their props to the children lately 😅

p-himik16:12:17

Yeah, I rather quickly decided against that practice. :) Not fun to have the whole 1000x100 table re-rendered just because one cell is changed.

p-himik16:12:30

And to "fix" my own reasoning about Hiccup driving React elements - while it is the case, props can indeed change without any changes in Hiccup, when a ratom is deref'ed outside of Hiccup, e.g. as in

(defn component []
  @state
  [:div "hello"])
Another thing worth mentioning is that re-rendering != calling render function. Those are separate. A render function being called does not lead to a re-render when the result is exactly the same - but one has to be certain that there are no things like lambdas there, because they aren't equal to one another even if they do the same thing.

juhoteperi16:12:53

Hmm, I'd say the calling render function is the same as re-rendering, even if the output doesn't change. Reagent creates the React elements again, and the React will do the check if any DOM updates need to be done.

p-himik16:12:30

> Reagent creates the React elements again Aren't they cached?

juhoteperi16:12:18

The elements itself, no, not at least by Reagent. React might optimize something. Reagent caches the fn -> React component instance (class or fn), Hiccup keyword parsing to element name + class + id, and property keyword to JS property name.

p-himik16:12:37

Ah, of course! Thanks. Confused with component caching.

juhoteperi16:12:47

For built-in elements, like :li, both are fine. I think pretty much all Reagent versions support this. (Reagent doesn't need to do anything here, if second vector element is a map, it is used as properties to the React element, and React will see the key.) For Reagent components (where the first vector element is a function) only the metadata works. (Here Reagent takes the key from metadata, and passes it to React element which refers to the component.)