Search code examples
reactjsreact-hooksrerender

Prevent rerender of sibling component which initiates a useState in wrapper component


I am not very experienced with React but I have a very simple Setup.

export default function App() {
  const [title, setTitle] = useState("still-empty");

  const myFunction = title => {
    setTitle(title);
  };

  return (
    <div className="App">
      <ComponentA myFunction={myFunction} />
      <br />
      <br />
      <ComponentB title={title} />
    </div>
  );
}



const ComponentA = ({ myFunction }) => {
  console.log("Rendering Component A");

  return (
    <div onClick={() => myFunction(Math.random() * 1000)}> Component A </div>
  );
};

export default ComponentA;


const ComponentB = ({ title }) => {
  return <div> Title : {title}</div>;
};

export default ComponentB;

Here is a sandbox to test this: https://codesandbox.io/s/musing-cookies-g7szr

See that if you click on "ComponentA", that exact ComponentA gets rerendered (you can see it in console) although no props are changed on this component. This is a simplified example of my real use case. In my real use case, ComponentA is a map where a lot of stuff (zoom, center) will be reset. I want to prevent these resets and also the 1 second it takes for rerendering. Therefor I present this simplified example.

So how do I pass an information from ComponentA to ComponentB, without rerendering ComponentA itself? Thanks for helping out here.


Solution

  • use useCallback in Parent so that the function is not created again and again but only on initial render. use React.memo so that when no props are changed the component wont re-render.

    App

    export default function App() {
      const [title, setTitle] = useState("still-empty");
    
      const myFunction = useCallback(title => {
        setTitle(title);
      }, []);
    
      return (
        <div className="App">
          <ComponentA myFunction={myFunction} />
          <br />
          <br />
          <ComponentB title={title} />
        </div>
      );
    }
    

    ComponentA

    import React, { memo } from "react";
    
    const ComponentA = ({ myFunction }) => {
      console.log("Rendering Component A");
    
      return (
        <div onClick={() => myFunction(Math.random() * 1000)}> Component A </div>
      );
    };
    
    export default memo(ComponentA);
    

    Working demo is here: https://codesandbox.io/s/affectionate-boyd-v7g2t?file=/src/App.js