Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

why this setState is unexpectedly passing the old value?

I’ve this parent component(Parent) which holds an inner component(InnerComp) (for organizing code). The inner component has another nested component(Comp) which I’m importing from another file. to update Parent‘s state from Comp, I’m passing the setParentCount function via prop in Comp

function Parent() {
  const [parentCount, setParentCount] = useState(0);

  const InnerComp = () => (
    <>
      <h2>necessary inner comp</h2>
      <hr />
      <Comp setParentCount={setParentCount} />
    </>
  );

  return (
    <>
      <h1>Parent</h1>
      <hr />
      <InnerComp />
      <p>parent comp count = {parentCount}</p>
    </>
  );
}

Comp has its own state as well. the "Click" button in Comp calls the handleClick function on click. the handleClick function is trying to update both the Comp and Parent‘s state. but it seems that compCount is not getting updated.

function Comp({ setParentCount }) {
  const [compCount, setCompCount] = useState(0);

  useEffect(() => {
    console.log(compCount);
  }, [compCount]);

  function handleClick() {
    setCompCount((prev) => prev + 1);

    setParentCount((prev) => prev + 1);
  }

  return (
    <>
      <h3>child comp</h3>
      <button onClick={handleClick}>Click</button>
      <p>child comp count = {compCount}</p>
    </>
  );
}

I’ve added the useEffect as well for compCount in Comp. it’s logging every time I click the button. but the same initial value. means the setCompCount function is setting the old value every time. I wonder why it is happening.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

When I add the InnerComp‘s JSX directly inside Parent instead of making a new inner component, it works fine. But I kinda need the InnerComp to keep my code organized.

I know I can make it work with useContext, but I think having context here will make this tiny component really heavy.

Here‘s a codesandbox

>Solution :

The problem is the InnerComp is getting renewed everytime the parent state updates. Updating the parent state triggers rerender of the parent component in which InnerComp is declared and rendered. That causes InnerComp and also Comp which is in InnerComp to be initialized everytime the parent state change. It is not a good way to declare a component inside a compoent.

To resolve this, you can move InnerComp component declaration outside of the Parent and pass the necessary props. If you don’t like passing the setParentCount props multiple times to child component you can consider using react context or state management libraries such as Redux, Recoil, etc.

const InnerComp = ({setParentCount}) => (
    <>
      <h2>necessary inner comp</h2>
      <hr />
      <Comp setParentCount={setParentCount} />
    </>
 );

function Parent() {
  const [parentCount, setParentCount] = useState(0);

  return (
    <>
      <h1>Parent</h1>
      <hr />
      <InnerComp setParentCount={setParentCount} />
      <p>parent comp count = {parentCount}</p>
    </>
  );
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading