skip to Main Content

So I currently have a component that looks like this:

<Parent>
<Child/>
</Parent>

However, sometimes I want to only return:
<Child/>

This could be done like this:

if (condition) {
return <Child/>
}

return (
<Parent>
<Child/>
</Parent>
) 

The problem is when condition is met (true) <Child/> will re-render. It’s a shame because none of the props/state inside <Child/> change and this component can be quite expensive to render.

I would prefer not to rewrite <Parent/> so that what is needed in it becomes a sibling to <Child/> as it’s a big change.

How would I go about stopping this unnecessary render of <Child/> each time condition is met.

I have tried to use React.memo but it wasn’t working how I expected.

2

Answers


  1. Unfortunately, I don’t think what you’re trying to achieve is possible, however you could do a workaround with similar functionality. Think about it like this: Instead of adding and removing the wrapper of the child (Parent), try to add and remove the siblings. It would be pretty much the same thing. I know you said that you’d like not to modify the code of Parent component, however I don’t think this is going to affect your code.

    Here’s an example:

    const Parent = ({
      children,
      state,
    }: {
      children: ReactNode;
      state: number;
    }) => {
      return (
        <>
          {state % 2 === 0 ? (
            <>
              <label>Sibling 1</label>
              <div>Sibling 2</div>
            </>
          ) : (
            ""
          )}
          {children}
        </>
      );
    };
    

    As you can see, instead of modifying everything I just add and remove the siblings.
    Also, remember to add useMemo to the child component:

    const Child = () => {
      const [childState, setChildState] = useState<number>(0);
    
      return useMemo(() => {
        console.log("Child re-render");
        return (
          <button
            onClick={() => {
              setChildState(childState + 1);
            }}
          >
            Child State: {childState}
          </button>
        );
      }, [childState]);
    };
    

    In this example, the child component should only re-render when childState is modified. If the state from the parent is modified, then only the siblings should be rendered. Here’s my full code:

    import { ReactNode, useMemo, useState } from "react";
    
    const App = () => {
      const [appState, setAppState] = useState<number>(0);
    
      return (
        <>
          <button
            onClick={() => {
              setAppState(appState + 1);
            }}
          >
            test
          </button>
          <Parent state={appState}>
            <Child />
          </Parent>
        </>
      );
    };
    
    const Parent = ({
      children,
      state,
    }: {
      children: ReactNode;
      state: number;
    }) => {
      return (
        <>
          {state % 2 === 0 ? (
            <>
              <label>Sibling 1</label>
              <div>Sibling 2</div>
            </>
          ) : (
            ""
          )}
          {children}
        </>
      );
    };
    
    const Child = () => {
      const [childState, setChildState] = useState<number>(0);
    
      return useMemo(() => {
        console.log("Child re-render");
        return (
          <button
            onClick={() => {
              setChildState(childState + 1);
            }}
          >
            Child State: {childState}
          </button>
        );
      }, [childState]);
    };
    
    export default App;
    
    Login or Signup to reply.
  2. Have you tried useMemo?

    const child = useMemo(()=><Child/>,[])
    
    if(condition) return child;
    
    //...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search