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

React useEffect useState only re-rendering some variables in iteration

I’m simulating a scenario of opening packs of cards. I have a UI that shows the amount of packs a user has. If the user has many packs, I have a function to open all the packs in a repetitive, quick motion. If the user chooses to ‘open all’, the user can see the contents of the pack for 1100ms, until the next pack open is rendered. Otherwise they would have to open all the packs individually, which could be time consuming.

After each pack open, I set the state of the UI to show the content of the pack and the amount of packs the user has. The content of the pack renders every time, however, the counter doesn’t. The counter updates at the very end. I’m curious as to why the data updates every iteration, but the counter doesn’t.

I toggle openAllMode:

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

  function openAll() {
    setOpenAllMode(!openAllMode);
  }

Then I useEffect:

  useEffect(() => {
    if (openAllMode) {
      Promise.all(getDataAsPromises()).then(() =>
        setTimeout(() => getUserPackCount(), 1100)
      );
    }
  }, [openAllMode]);

  function getDataAsPromises() {
    return Array(packCount)
      .fill(null)
      .map((c, i) =>
        new Promise((resolve) => setTimeout(resolve, i * 1100)).then(() =>
          getData()
        )
      );
  }

  function getData() {
    getRandomData(1)
      .then((data) => {
          setData(data);
          setPackCount(packCount - 1);
      })
      .then(
        () => {
          console.log("Opened Pack!");
          setOpen(true);
        },
        (error) => {
          console.error("Error Opening Pack: " + error);
          setOpen(false);
        }
      );
  }

Basically, every 1100ms, the state of ‘setData’ is re-rendering. However, the state of ‘setPackCount’ isn’t re-rendering until the end.

>Solution :

You’ve a stale enclosure over the packCount state. The issue is that packCount is closed over in getDataAsPromises callback scope and each setPackCount(packCount - 1); is just overwriting the previous state update within the loop.

Use a functional state update to correctly reference any previous state.

setPackCount(packCount => packCount - 1);
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