Fork me on GitHub
#reagent
<
2022-02-15
>
lambder10:02:59

hello, just read the https://github.com/reagent-project/reagent/blob/master/doc/WhenDoComponentsUpdate.md to understand why my component is re-rendering

lambder10:02:34

the article says that if the parameters stay the same the component should not re-rendeer.

lambder10:02:01

what i have noticed is that if my component has inline function as a param:

lambder10:02:24

[:div.form-floating.mb-3
           [autocomplete
            {:on-place-changed  update-start-place}]]

lambder11:02:21

higher in the let form I have:

lambder11:02:26

update-start-place         (fn [place]
                                     (when place.formatted_address
                                       (reset! start-place place)))  

lambder11:02:11

even when the start-place ratom value changes my component doesn't re-render - as expected

lambder11:02:26

but if my component is defined with the inline function:

lambder11:02:47

[:div.form-floating.mb-3
           [autocomplete
            {:on-place-changed (fn [place]
                                 (when place.formatted_address
                                   (reset! start-place place))}]]

lambder11:02:10

then this component re-renders every-time the start-place atom is updated.

lambder11:02:16

Why is that?

wevrem15:02:44

Even though you, as a human, can see that the inline function here still is logically the same, every anonymous function is always not= to every other because they are distinct objects in memory.

(= #(+ 1 1) #(+ 1 1))
;;=>false

lambder11:02:56

is it because the update to the parent components cause redefinition of the :on-place-changed function?

lambder11:02:35

and since reagent uses = to check if params changes it decides that the :on-place-changed has changed?

lambder11:02:20

they have:

lambder11:02:23

(defn more-button
  "I'm a button labelled 'More' which increments counter when clicked"
  [counter]                                ;; a ratom
  [:div  {:class "button-class"
          :on-click  #(swap! counter inc)} ;; increment the int value in counter
   "More"])  

lambder11:02:40

there :on-click also uses inline def function

lambder11:02:55

and they claim this component don't re-render.

lambder11:02:07

any idea, please?

wevrem15:02:47

The reason why the more-button component doesn’t re-render is explained a little further down in that section. Basically its input, counter, has not changed. Another source explaining this same concept is the re-frame section on improving performance: https://day8.github.io/re-frame/Performance-Problems/#4-callback-functions

lambder12:02:38

@UTFAPNRPT, but if the parent re-renders, it generates new hiccup thus creates new closure (inline functions), which are passed to the components as the parameters, right? These newly generated functions (listeners) will result false during params comparison, which will make the child component re-rendeer as well. correct?

lambder12:02:59

@UTFAPNRPT the link you provided describes the effect precisely. My issue is not low performance tho. Each render of my component (google autocomplete) calls google api and binds to the element via :ref this causes the google places autocomplete being created every render.

lambder12:02:19

I'll try to tackle the problem with the class based component and the lifecycles.

lambder12:02:40

ah, Form-3: A Class With Life Cycle Methods is no help here unfortunately

wevrem19:02:16

If the parent re-renders, yes, it generates new hiccup, but it still calls more-button with the exact same property as the prior call, which is the ratom counter, which hasn’t changed. I’m not making this up, I’m just repeating the description in https://github.com/reagent-project/reagent/blob/master/doc/WhenDoComponentsUpdate.md#a-combination of the documentation for reagent.

lambder11:02:31

(additional info: in my autocomplete component I use :ref, can that be the reason?)

Akiz17:02:48

Hi here, i need to create

<a-component name></a-component>
With HICCUP I can do
[:a-component {:name ""}] 
but this doesn’t seem to work with Reagent. How should I do it?

p-himik17:02:03

Do you mean <a-component name>? If so, then it's just [:a-component {:name true}].

Akiz17:02:35

Yeah, double quotes is a mistake. Thanks

👍 1
Akiz17:02:46

But it doesn’t work for me..

[:a-box {:scale-on-mouse-enter true :color "#AAAAAA" }]
is rendered as
<a-box scaleonmouseenter="true" color="#AAAAAA"></a-box>

p-himik17:02:51

Let's take a step back. What are you trying to achieve with that? What's a-box, what attributes does it expect originally, how is it used in JS, if at all?

p-himik18:02:57

Is it a custom element that has a corresponding entry in customElements?

Akiz18:02:10

It is part of a-frame library, there are components like <a-box> etc. You can define your own component like scaleonmouseenter and attach it to an existing component. For example <a-component extra-component {:position … :width …}></a-component> any extra-component must be registered first via a-ftame functions

Akiz18:02:34

like

<a-scene>
  <a-entity hello-world></a-entity>
</a-scene>
AFRAME.registerComponent('hello-world', {
  init: function () {
    console.log('Hello, World!');
  }
});

p-himik18:02:57

Alright, so those are custom elements, nice. I wanted to exclude the option where :a-box was actually supposed to be a-box in Hiccup. :) Replace that :scale-on-mouse-enter keyword with a "scale-on-mouse-enter" string. Reagent treats keywords differently.

Akiz18:02:30

Thank you, this looks right!

👍 1
Akiz19:02:41

So I ended with [:a-box {"scaleonmouseenter" ""}] if I do [:a-box {"scaleonmouseenter" true}] It fails with an error from “scaleonmouseenter” component:

aframe-master.js:9749 Uncaught TypeError: Cannot read properties of undefined (reading 'x')…. 
😳

p-himik19:02:18

Weird. Dunno why.

👍 1
Michaël Salihi17:02:27

Instead try [:a-component "name"]

Akiz18:02:00

Doesn’t work for me..

[:a-box "scale-on-mouse-enter" {:color "#AAAAAA" }]
is rendered as
<a-box material="" geometry="">scale-on-mouse-enter{:color "#AAAAAA"}</a-box>