Tuesday, 10 November 2020

React updating progress from a compute intensive function using setState

I have a simple React class showing this.state.progress (a number) and this state can be updated via updateProgress(progress) function.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      progress: 0,
    }
  }

  updateProgress = (progress) => {this.setState({progress}); };
  render() {
    let {progress} = this.state;
    return <h1>{progress}</h1>;
  }
}

I have a compute intensive function myHeavyFunc, for which I need to show the progress bar. I call updateProgress function I mentioned above using the loop variable inside myHeavyFunc.

myHeavyFunc = async (updateProgress) => {
    let loopLength = 1000000;
    updateProgress(0);
    for(let i=0; i<loopLength; i++) {
      // some processing happens here
      updateProgress((i+1)/loopLength);
    }
}

What happens is that state gets updated, and I can confirm that by console logging progress in the setState callback, but the component doesn't re-render until the very end. However, if I include a small sleep of 1ms, then the re-render happens, progress updates (obviously with a huge loss in time, which I do not prefer).

JSFiddle here. Here I run myHeavyFunc on clicking the progress number. You can see that when await sleep(1) is commented, onClick finishes in a second, but does NOT show progress. It does not even change for any subsequent clicks. On the other hand, if it is not commented, I get the progress updates, but it just takes forever to complete!

I am aware that React shall batch the updates for performance reasons, but in my case, I can't even see one update happen till the whole loop finishes. Also, please note that I am NOT looking for a synchronous setState function, but I need re-rendering (atleast on the progress element alone) after the state is set. I am fine if it drops a few progress updates due to batching, but I do expect it to show progress.

Is there a way to run myHeavyFunc in a non-blocking manner while updating the progress in the UI? What is the right way to update progress of compute intensive functions in React?



from React updating progress from a compute intensive function using setState

No comments:

Post a Comment