Monday, 9 October 2023

React client-side rendered components - state doesn't update while script is still running

I don't have a reproducible example for this but basically what I'm doing is this:

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    let that = this;
    fetch(...).then((response) => {
      response.json().then((data) => that.setState(data);)
      window.setTimeout(that.tick.bind(that), 1000);
    });
  }

  tick() {
    /* do some calculation to update the state */
    let state = {...};
    this.setState(state);
    console.log("Set state: ", state);
    if (someCondition)
      window.setTimeout(this.tick.bind(this), 1000);
  }

  render() {
    console.log("Render state: ", this.state);
    return ( ... react output ... );
  }
}

I fetch some data, add it to the state, then start a timer that calls tick() once per second. tick() updates the state, logs the new state (note - the value I'm setting not the value of this.state) and then decides whether to set a new timer. render() logs what its idea of the state is and then returns the rendered content.

This all works. I can see in the console the state value I'm setting and then render()'s idea of the state being the same as that value I've just set.

The problem comes when I run it all through webpack to create a single JS bundle. Then setState() stops doing what I expect. I can still see the value that I'm feeding to setState() but the state value seen by render() is {} until I stop setting new timers. Then the state value seen by render() updates and the content renders correctly.

The output of webpack is pretty impenetrable so I'm having a bit of trouble tracking down what has changed to cause this difference in behaviour. Is this a well-known gotcha?

I'm aware that setState() is not guaranteed to be synchronous and that I shouldn't expect the value of this.state to update immediately - but I did expect it would at least have updated by the time render() is next called.



from React client-side rendered components - state doesn't update while script is still running

No comments:

Post a Comment