React component not rerendering after state change, but render() is being called

Viewed 506

So I have a method that takes a while to finish (>20 seconds), its doing a bunch of math and CPU heavy stuff, that's why it takes so long. While it is running, it calls setState several times and the state correctly updates and render() is called. However, the component isn't rerendered on the web page, but it does rerender after the method finishes.

I'm fairly sure that the method is pegging the CPU and React is not rerendering because of that. Is there a way to pause the execution of the method for a little bit in order for the webpage to rerender? Or is there a way to force the page to rerender?

class FibonacciPage extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      n: 0
    }
    // compute to 1000th place
    this.nth = 1000
  }

  fibonacci(nth) {
    console.log(nth)
    this.setState({
      n: nth
    })
    if (nth < 2) {
      return 1
    } else {
      return this.fibonacci(nth - 1) + this.fibonacci(nth - 2)
    }
  }

  componentDidMount() {
    this.fibonacci(this.nth)
  }

  render() {
    console.log("RENDER")
    return ( <p> {this.state.n} </p>
    )
  }
}

ReactDOM.render(<FibonacciPage />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

This snipped may not show its point in the browser because it uses console.log and I don't know if you can see that.

1 Answers

It's not that it's pegging the CPU (though of course it could be pegging one of the cores), it's that there's only one browser thread used for running your JavaScript and updating the page display. As long as your method is running, the browser can't update the display of the page.

Is there a way to pause the execution of the method for a little bit in order for the webpage to rerender? Or is there a way to force the page to rerender?

To do that, you have to:

  1. Break your function up into chunks and run each chunk separately, using setTimeout or similar to schedule the next chunk. By doing that, you let the thread exit your JavaScript code and get used by the browser to repaint the page.

    or

  2. Move your computationally-heavy code to a web worker (spec, MDN), so it can run in parallel with page updates, keeping your page responsive even though the method is doing heavy computation.

Related