DEV Community

Discussion on: Updating React State Inside Loops

Collapse
 
ecyrbe profile image
ecyrbe • Edited

Hello Adam,

Nice article as always.
You can also just do this if i'm not mistaken :

export const useSlowProcess = () => {
  const { setProgress, setShowProcessing } = useContext(AppState);

  const runSlowProcess = async () => {
    const startTime = Math.round(Date.now() / 1000);
    setProgress(0);
    setShowProcessing(true);

    for (let i = 1; i < 101; i++) {
      for (let j = 1; j < 1001; j++) {
        for (let k = 1; k < 1001; k++) {
          for (let l = 1; l < 1001; l++) {
            // do the stuffs
          }
        }
      }
      console.log(i);
      setProgress(i);
      await Promise.resolve(); // give back the hand to javascript to schedule another task like react refresh, etc
    }
    setShowProcessing(false);
    console.log(
      "Elapsed time:",
      Math.round(Date.now() / 1000) - startTime,
      "seconds"
    );
  };

  return {
    runSlowProcess
  };
};
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bytebodger profile image
Adam Nathaniel Davis

NO. If you pop over to the Codesandbox, you can prove out that this doesn't work. And that's part of what made this so confusing for me to solve when I first encountered it, because I was thinking the same thing. As was noted above in a prior comment, you can find an explanation of this concept on this page:

web.dev/optimize-long-tasks/

Specifically, the page provides this helpful explanation:

Caution
While this code example returns a Promise that resolves after a call to setTimeout(), it's not the Promise that is responsible for running the rest of the code in a new task, it's the setTimeout() call. Promise callbacks run as microtasks rather than tasks, and therefore don't yield to the main thread.

In other words, the Promise alone is not sufficient to fix this "problem". You need the setTimeout() returned in the Promise.