splunk
splunk

Reputation: 6815

setState method causes "Warning: setState(...): Can only update a mounted or mounting component.." error

In following code cityNameLength is a number and represent the length of the name of one city. My goal is to render multiple elements based on cityNameLength value. So if cityNameLength is equal to 5 I'd like to have 5 span elements.

This is what I've have:

class myCitiesClass extends Component {
  constructor(props) {
      super(props);
      this.state = {cLength: 0};
      this.setState({ cLength: this.props.cityNameLength });
  }


  renderDivs() { 
    var products = []

    var cNameLength = this.state.cLength
    for (var p = 0; p < cNameLength; p++){
      products.push( <span className='indent' key={p}>{p}</span> );
    }
    return products
  }

  render() {    
    return (
      <View>
        <Text>City name length: {this.props.cityNameLength}</Text>
        <View>{this.renderDivs()}</View>
      </View>
    );
  }
}

This is the error I get:

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.

Upvotes: 1

Views: 1017

Answers (2)

gaperton
gaperton

Reputation: 3826

You cannot use this.setState in the constructor. And fortunately, you don't need to. State could be set to the proper value right in the assignment:

constructor(props) {
      super(props);
      this.state = { cLength: this.props.cityNameLength };
}

However, this code is not good too. Assigning state from props is not necessarily the mistake, but you have to know well what you're doing and why (thing is that props could be changed from the top level component at any time, and you will have to keep state in sync with overridden componentWillReceiveProps() to make your component work right). If you doubt you do, you should avoid it.

In your case it should be easy as you don't need state at all. Remove constructor, and use this.props.cityNameLength instead of this.state.cLength.

And when you modify state from componentDidMount() you are supposed to know very well what you're doing (because you're triggering another render right after your component is just rendered - why?). In 99% of cases it's the mistake. Not that fatal as doing so in componentDidUpdate, though.

Upvotes: 0

Matt Aft
Matt Aft

Reputation: 8936

There are two ways you can do this. If you want to render the spans before the component is mounted, get rid of the setState and just do this in the constructor:

this.state= {cLength: this.props.cityNameLength };

If you want the component to mount first - then remove the setState from the constructor and move it into componentDidMount():

componentDidMount() {
  this.setState({ cLength: this.props.cityNameLength });
}

Upvotes: 1

Related Questions