4

In my (class) component I want to show Loading spinner for the duration of the _expensiveFunction. Value isLoading was changed in the state before the function was executed, but it will not be re-rendered (spinner does not spin) until _expensiveFunction is complete.

I tried it with componentDidUpdate and forceUpdate, but without success.

_makeCalculation() {
  this.setState(
    { isLoading: true },
    () => this._expensiveFunction(),
  );
}


_expensiveFunction() {
  console.log(this.state.isLoading); // => true
  // ***
  this.setState({ isLoading: false });
}
Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43
john_per
  • 320
  • 6
  • 16
  • Hello, can you share the code how you are using `isLoading`, after fetching your data make your `setState` function synchronous like you did in `_makeCalculation` – octobus Aug 01 '19 at 14:38
  • 1
    Why don't you set the state before the expensive part in `expensiveFunction` to `isLoading: true`? – devserkan Aug 01 '19 at 14:43
  • @devserkan tried that, without success. – john_per Aug 01 '19 at 14:55

1 Answers1

3

A common trick is to rely on setTimeout():

_makeCalculation() {
  this.setState(
    { isLoading: true },
    () => setTimeout(this._expensiveFunction, 0),
  );
}
Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43
  • This is working, could you explain why? And is there any other solution or I have to stick with setTimeout? – john_per Aug 01 '19 at 14:57
  • 2
    Javascript is single-threaded. If an event is triggered, it can only run when the currently running code has finished. Using setTimeout with a zero time delay effectively tells the JS interpreter that the callback function call is part of a new context and that your current code block is finished. This means that JS will take the opportunity before calling callback() to check to see if any other events need to be handled. – Mosè Raguzzini Aug 01 '19 at 15:03