Ant
Ant

Reputation: 836

Stop child update after parent unmounted

Small issue - unsure how to handle stopping a child from updating after its parent has been unmounted.

Currently I have a 'view' (parent) with a TextField component nested.

My TextField component implements an input with onBlur

<input type={this.props.type} name={this.props.name} onBlur={this.handleBlur} ... />

Two functions in the TextField component are

hideClear: function () {
    // to prevent clear button from disappearing when clicking on it
    if (!this.state.keepFocus) {
        this.setState({inFocus: false});
    }
},
handleBlur: function (e) {
    e.preventDefault();
    this.setState({keepFocus: false});
    window.setTimeout(this.hideClear, 200);
},

Now, when my parent unmounts while my input field has focus, I get back

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the TextField component.

I'm hoping I might get some good suggestions about how to handle this scenario.

Thanks :)

Upvotes: 1

Views: 798

Answers (1)

Diego Zacarias
Diego Zacarias

Reputation: 793

As the error says, you are trying to update the component's state when the component has already been unmounted, this is due to the timer you have in the handlerBlur() function.

I'd like to think, I'm not so sure, but whenever the component gets unmounted the input loses focus and so the onBlur event gets triggered firing your handleBlur() function, thus setting a timer with setTimeout to essentially update the component's state after it has already been unmounted, through the hideClear() function.

An optimal solution would be to find places where setState() might be called after a component has unmounted, and fix them. Such situations most commonly occur due to callbacks, when a component is waiting for some data and gets unmounted before the data arrives. Ideally, any callbacks should be canceled in componentWillUnmount, prior to unmounting.

The above quote was extracted from the React developer's blog.

A quick way to fix this would be store the timer's identifier in an instance variable so as to get the timer cleared later using window.clearTimeout when the component is to be unmounted.

var MyComponent = React.createClass({

  timerId = 0,

  ...

  handleBlur: function (e) {
    e.preventDefault();
    this.setState({keepFocus: false});
    this.timerId = window.setTimeout(this.hideClear, 200);
  },

  componentWillUnmount: function() {
    if (this.timerId) 
      window.clearTimeout(this.timerId);
  },

  ...

}

Upvotes: 1

Related Questions