ParthianShotgun
ParthianShotgun

Reputation: 602

How are function calls and component calls different in React?

https://codesandbox.io/s/cocky-silence-486sh?file=/src/App.js

In the above example, we see that calling the ChildWrapper as ChildWrapper() vs <ChildWrapper/> causes some differences.

The function method behaves as intended, so when I increment the counter, the reference stays the same, however using the component call, it actually remounts.

I was wondering if my intuition is correct, that the references are changing, and more important why are they changing. And to add on to that, which should be the preferred method for rendering functions that returns jsx, <Component/> or { Component() }.

Upvotes: 1

Views: 174

Answers (2)

Incepter
Incepter

Reputation: 2958

When you do <ChildWrapper/> it is translated to React.createElement(ChildWrapper, {}, null) which means you ask react to create an element for you.

When you do ChildWrapper() you are just calling a function, react does not know about this and cannot know about it, so you won't have any of react's features (hooks).

With your example, with logging the two results in the console you will see this, and you can notice that the difference is noticeable:

enter image description here

  • When calling the function, it will return a <div>, here, jsx will transpiles it to an object with type div.
  • When calling it via jsx from the start, it will return an object with type ChildWrapper.

PS: you are creating the ChildWrapper inside a component (during render) So it will have a new value each time your Parent component renders, and react after rendering and going into reconcialiation, it will remove the whole previous tree and create a new one, because the type changed.

Let's sum up all what I've wrote:

  • The child "behaving correctly for you" is the function call, because you basically call it and it returns a div, react after render and during reconciliation, finds a div and then just updates it if there is a change. So the mount useEffect(() => ..., []) will not be executed.

  • Why the child created with jsx isn't behaving correclty ? because you are dynamically creating its type, so at each render, it will create a new ChildWrapper Type, and react during reconciliation will remove it entirely because its type changed, and thus, the mount useEffect(() => ..., []) will be executed each time, because every time we mount a new element.

Read more about reconciliation in this link

Upvotes: 3

Treycos
Treycos

Reputation: 7492

From the official documentation :

Each JSX element is just syntactic sugar for calling React.createElement(component, props, ...children). So, anything you can do with JSX can also be done with just plain JavaScript.

Internally, the code generated looks like this: React.createElement(Component, { props }, children),

The createElement function will then register and render the component you gave to it, bind it with the shadow DOM and update it whenever it is necessary. It will also pass its props and children arguments.

But if you call your component directly, none of that happens, your component will not be correctly rendered and updated by react because it lacks the core features given by createElement.

Upvotes: 1

Related Questions