5

I know that an error is thrown when setting state for a component not yet mounted. Which explains the error I get from using setState function as oppose to explicitly and directly setting the state.

import React, {Component} from 'react';

class SearchBar extends Component {

constructor(props) {
  super(props);

  this.state = {term: ''}; // -> seems to be the agreed means to set   initial state
// this.setState({term: ''}); // -> generates an error
}

render() {
  return (
    <div>
      <input onChange={event => this.setState({term:   event.target.value})}/>
      Value of the input: {this.state.term}
  </div>
);
  }
}

The error I get when I uncomment the second line this.setState({term: ''}) is:

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 component.

I know how to prevent the error, simply by setting state explicitly without telling React anything about it and I have already seen the github issue talking about the bug: Github Issue #3878 What I want to know though is why cant React work it out? if one calls setState from a constructor it knows this is the first time its being used? I am probably simplifying it way too much, but if anyone has a nice technical answer as the reason why not?

1
  • 2
    setState triggers a long and complicated process of delayed re-rendering. As a wild guess - they just did not want to complicate the process (even further) that would in turn give 0 benefits. Commented Apr 7, 2016 at 22:27

1 Answer 1

11

React classes have always initialized with a property called state set to a value of null as seen in the source code. As you know, React provides a setState method for manipulating this property. According to the docs:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate().

In short, setState() is an asynchronous, multi-step, unpredictable operation that will cause component rerenders. To call such a function would require an object to already be fully initialized and thus couldn't happen while the class is still mounting. It would already try to perform lifecycle operations on the class before it was fully initialized.

Of course, that leaves an issue if you want a component to start out with a state that is not null and yet don't want to immediately cause multiple renders and operations to take place. That is why React provides a way to initialize a component state without relying on setState. In ES5, this was setting the initial state inside of a property called getInitialState. However, ES6 introduced a native syntax for setting properties when a class is initialized with a special constructor method (so React no longer had need of its own custom version). That is why, if you want to initialize a React component with a state when it is mounting, you must declare it as this.state = {} and not use setState().

Sign up to request clarification or add additional context in comments.

3 Comments

You beat me to it, well said.
@andy-noelker awesome, thank you for the answer which is very clear. I feel much more comfortable using a library knowing why doing something one way as oppose to another is imoprtant, that you have made clear to me. thanks.
@Faktor10 glad I could help! If you feel like this answers the question, could you go ahead and mark it as accepted so that others who find this question can see?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.