3

I have a long running task in Javascript. React should rerender the component on several points between the tasks. But it rerenders only at the end of the whole task. How to make React rerender the page on all setState() calls?

A simplified example:

setStatePromise = (state) => new Promise(resolve => {
    this.setState(state, () => resolve());
});
longRunningTask = async () => {
    await this.setStatePromise({progress: 1}); // not shown to the user
    await doMuchWork();
    await this.setStatePromise({progress: 2}); // not shown to the user
    await doEvenMoreWork();
    await this.setStatePromise({progress: 3}); // shown to the user when everything is done
};
onButtonClick = async () => {
    await this.longRunningTask();
}

Here is a working example showing the problem:

https://codesandbox.io/s/intelligent-cori-31qn5

A workaround I used before is:

setStatePromise = (state) => new Promise(resolve => {
    this.setState(state, () => {
        setTimeout(() => resolve(), 1);
    });
});
Lazar Nikolic
  • 4,261
  • 1
  • 22
  • 46
Michael
  • 2,528
  • 3
  • 21
  • 54

2 Answers2

1

The "Render" method is called continuously. The problem is because Javascript is single-threaded.

Loop inside doMuchWork is blocking main thread (and UI as well).

How to do a loop in Javascript that doesn't block the UI?

A quick approach to the problem is to split the algorithm inside doMuchWork (if it's possible) into steps/chunks: https://codesandbox.io/embed/nostalgic-wiles-g38ce, but it has a lot of cons.

setTimeout is allowing other methods, etc. to do their job (like refreshing UI) putting callback later in the queue and that's why solution with setTimeout(..., 1000) given in this topic worked well.

Other (better) approaches are to use suggested generators or to use Web Workers created especially to do such time-consuming work.

Something about your problem with a solution using Web Workers.

trebor
  • 724
  • 5
  • 16
0

You do not return your promise in longRunningTask, that is one of the reasons, but that wont work either. A generator could solve this, yielding promises every time it is necessary.

Daniel Tok
  • 207
  • 1
  • 9