As far as I understand, make
will be called every time the <Greeting>
component is used in a parent component render method, so it will be called multiple times.
Yes, make
is called for every render.
In this example, make Inside
is printed in the console every time the button is pressed –which causes a new render of the Inside
component.
I was curious to understand better why this was happening, so sharing it here in case someone else finds it interesting. The way the implementation works today is approximately as follows:
<Greeting name="John" />
is transformed into ReasonReact.element(Greeting.make(~name="John", [||]))
by the Reason ppx. You can find the implementation in the main Reason repo.
- In that statement,
Greeting.make
is the make
function you are making reference to, the same function that each ReasonReact component has to define.
ReasonReact.element
is where the magic happens. This function will call createElement
the following way (source code):
createElement(
component.reactClassInternal,
~props={"key": key, "ref": ref, "reasonProps": element},
[||]
)
- The
element
passed as the prop reasonProps
is actually the full component "template" that is returned by make
(see the assignment a few lines above).
component.reactClassInternal
points to a React component that I will be calling WiringComponent
for simplicity. What this WiringComponent
does in essence is to declare all React lifecycle methods and implement them by just delegating the actual behavior to the functions that come from the "template" declared with make
. These functions are picked from the reasonProps
prop that is passed to this WiringComponent
. You can see the implementation of this component here.
So, even if make
is called once for every render as you mention, in reality what is being rendered is something like <WiringComponent reasonProps=Greeting.make(...) />
. Then, when WiringComponent.getInitialState
is called (just once per component instance, as usual), it will delegate that call to Greeting.initialState
.
But this also means the component record will create multiple times the initialState
function right?
That's what the code seems to be doing. Solving this doesn't seem trivial to me. Given that labelled arguments are being used to model the components props, there is no way to memoize make
without giving up the type safety, as there can be many "flavors" of this function (one for each component).