2

Whats the difference between passing a ReactElement as a property:

First case

<RenderParam ReactElement={<Counter />} />

function RenderParam({ ReactElement }) {
  return <div>{ReactElement}</div>;
}

and passing a function that returns a ReactElement:

Second case

const instantiatedCounter = () => <Counter />; 

<RenderParam ReactElement={instantiatedCounter} />

function RenderParam({ ReactElement }) {
  return <div> <ReactElement /> </div> 
}

I see there are differences in the lifecycle:

  • Every time the parent react element updates, the mount cycle of Counter is executed for the second case:
ReactElement changed (at RenderParam lifecycle)
component did mount (at Counter)
  • Also the second case lose its state every time the parent component renders.

I dont see whats difference between them. Why first case its able to keep its state?

Rashomon
  • 5,962
  • 4
  • 29
  • 67

2 Answers2

2

This is actually rather simple, the real thing here is the timing of the rendering itself.

lets start from the second case, this is actually a design pattern called Render Props, you can read about it here: https://reactjs.org/docs/render-props.html in this case, the prop contains a function that returns a React Element, which means that It will be evaluated only when you invoke that function and thus it is not always "alive" like in your first case.

First case: when you bind your prop to an Element, it gets evaluated upon the creation of the parent element. which means that as long as the parent element is "alive" the prop element will be alive.

fadeys.work
  • 499
  • 4
  • 13
2

The first example passes a static JSX element <Counter /> as RenderParam prop. The second example uses a function instantiatedCounter, that allows to return a more dynamic JSX element, commonly referred to as Render props.

In the second case you lose state, because React treats the ReactElement prop as a freshly defined component every time, unmounts the old one and mounts it again on every render cycle. What you want to do is call the ReactElement prop to retrieve a JSX element as return value:

function RenderParam({ ReactElement }) {
  return <div>{ReactElement()}</div>; 
  // not: return <div><ReactElement /></div>
}

You could as well define it with JSX syntax <div><ReactElement /></div>. But then make sure, instantiatedCounter is a static function and not re-created on every render, so the object reference stays same:

const instantiatedCounter = () => <Counter />; 
// make it static in some way, so object reference doesn't change

export default function App() {
  // .. and remove instantiatedCounter here
  return <RenderParam ReactElement={instantiatedCounter} />
}
ford04
  • 66,267
  • 20
  • 199
  • 171