Child Component Remount even they mounted on Parent Component

24 Views Asked by At

Consider this simple code where I create three component.

  1. Parent Component (App) which create a <GrandChild /> element and pass as the children of <Child />
  2. Child component which has it's local state where I used to make the child component rerender on button click.
  3. GrandChild component where a dum component which only has the debug logs to identify when it's mount, unmount.
import { useEffect, useState } from "react";

export default function App() {
  const gc = <Grandchild />;
  console.log("render parent");

  useEffect(() => {
    console.log("Parent mounted");

    return () => {
      console.log("Parent unmount");
    };
  }, []);

  return (
    <div>
      <Child>{gc}</Child>
    </div>
  );
}

export function Child({ children }) {
  const [count, setCount] = useState(0);

  console.log("Child render");

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count me {count}</button>
      {children}    {*/ <===== this is line 20 and change this as per the comment below /*}
    </div>
  );
}

// if in line 20 changed to `{count % 2 === 0 && children}`, the GrandChildren
// alwasy remount when it visible.

export function Grandchild() {
  useEffect(() => {
    console.log("Grandchild mounted");

    return () => {
      console.log("Grandchildren unmount");
    };
  }, []);

  return <div>I'm the grand child</div>;
}

As per my understanding, the component is getting mounted when it's called with < /> tags like <GrandChild /> if it's called, it returned the react element which we can use anywhare without remounting it. If I'm correct, in the given setup, the GrandChild component is mounted only when the Parent component mounted.

but if I do the changes as per the comment to conditionally add / remove the children element in the Child component, the GrandChild component is unmount and remount again.

How could that be possible ?

Ideally the GrandChilde component should not remount. How can we avoid this Grand Child element is being remounting ?

1

There are 1 best solutions below

0
Nicholas Tower On

As per my understanding, the component is getting mounted when it's called with < /> tags like <GrandChild />

<GrandChild /> on its own does not mount a component. All it does is create a small object in memory which is instructions for react. It looks roughly like this:

{
  type: GrandChild,
  props: null
}

Typically what you do next is return that object as part of the render output of a component. Once react has finished building the tree of these objects (called the "virtual dom"), it does a step called reconciliation, where it will compare the virtual dom you just returned with the one from the last time it rendered. It's only going to compare the things you returned; it doesn't know what calculations you did along the way.

If reconciliation reveals that the previous render returned no <GrandChild/> at a certain spot and now there is one, then react mounts an instance of a GrandChild. If there was one before and now there isn't, then the instance gets unmounted.


When you do the version with count % 2 === 0 && children, on one render you're returning the <GrandChild />, and on the next render you aren't. This is exactly how you tell react to unmount a component. The fact that you created a <GrandChild /> in the middle of the code and then threw it away is unknown to react; it just uses what you returned.

Ideally the GrandChilde component should not remount.

If you don't want it to remount, then you must always return it. Maybe you can style it to be hidden, but it must be in the return from the component, in the same spot as last time.