Where to Initialize State in React

By Dave Ceddia Comment

Ahh, the many ways of initializing state… It can be confusing. Do you put the state = {...} directly inside the class, or do you write a constructor and say this.state = { ... } inside the constructor? And do you need to have a constructor at all?

2 Ways to Initialize State

There are two ways to initialize state in a React component: inside the constructor, and directly inside the class. Here are a couple examples.

Inside the Constructor

Initializing state inside the constructor looks like this:

class App extends React.Component {
  constructor(props) {
    // Required step: always call the parent class' constructor
    super(props);

    // Set the state directly. Use props if necessary.
    this.state = {
      loggedIn: false,
      currentState: "not-panic",

      // Note: think carefully before initializing
      // state based on props!
      someInitialValue: this.props.initialValue
    }
  }

  render() {
    // whatever you like
  }
}

When the component class is created, the constructor is the first method called, so it’s the right place to initialize everything – state included. The class instance has already been created in memory, so you can use this to set properties on it.

This is the one place where it is acceptable to have this.state on the left side of an equal sign. Everywhere else, you should always use this.setState instead of doing this.state.whatever = ... – that way, React will know that you’ve changed something, and it can re-render the component.

One important thing to note when you write a constructor is to make sure to call the parent class’ constructor: the super(props) line in the example above. The default constructor (provided by JS when you create a class) automatically calls super with any arguments passed in.

By writing your own constructor, you’re overriding that default behavior, and unless you call super yourself, it could lead to bugs if the parent needed to do some initialization.

Initializing State from Props

In most cases, this is an antipattern. Don’t “copy props into state.” It creates a second source of truth for your data, which usually leads to bugs. One source of truth is best.

Components will already re-render when their props change, so there’s no need to duplicate the props as state and then try to keep it up to date.

// Don't do this:

class BadExample extends Component {
  state = {
    data: props.data
  }

  componentDidUpdate(oldProps) {
    // By duplicating the data, you have to then
    // keep the local copy in sync with the
    // updated props...
    if(oldProps.data !== this.props.data) {
      // This triggers an unnecessary re-render
      this.setState({
        data: this.props.data
      });
    }
  }

  render() {
    return (
      <div>
        The data: {this.state.data}
      </div>
    )
  }
}

// Do this instead:

class GoodExample extends Component {
  render() {
    return (
      <div>
        The data: {this.props.data}
      </div>
    )
  }  
}

So, is it ever ok to initialize state based on props? Yes. The original version of the React docs mentioned this:

However, it’s not an anti-pattern if you make it clear that the prop is only seed data for the component’s internally-controlled state.

Think of it this way: it’s fine if the state needs a starting value which the component will then control. Ask yourself: does this component “own” the data? Does it just need a jump-start from a prop? Those are good reasons to initialize state from a prop.

An example of this is uncontrolled inputs with a default value. When you render an input this way, it initializes its internal state with the defaultValue prop:

<label>
  Name:
  <input
    type="text"
    defaultValue="Nobody"
    ref={c => this.nameInput = c}
  />
</label>

If you need to write a similar component yourself, consider initializing state from props.

Is a constructor required?

You aren’t required to write one, because JS provides a default constructor. To see how this works, try running these 3 lines in your browser’s console:

class Parent { constructor(arg) { console.log('constructing Parent with', arg) } }
class Child extends Parent {}
new Child(5);

Notice how it prints “constructing Parent with 5” when you create a new Child, even though Child has no explicitly-defined constructor, and doesn’t explicitly call the parent’s with super(arg). This super call is handled by JS automatically when you don’t define your own constructor.

Directly Inside the Class

The second way to initialize state is directly inside the class definition, using a class property. Here’s what that looks like:

class App extends React.Component {
  state = {
    loggedIn: false,
    currentState: "not-panic",
    someDefaultThing: this.props.whatever
  }

  render() {
    // whatever you like
  }
}

Nice and clean! A couple things to note here:

  • There’s no constructor
  • The state property is referenced directly. It’s not this.state, just state.
  • The scope is inside the class, but not inside a method.
  • You can still refer to this.props (and this.context).
  • This is a class instance property, as opposed to a static one, which you might use for propTypes (e.g. static propTypes = {...}).

As I’m writing this, the class property syntax is a Stage 3 proposal so it’s not part of the official JS spec yet. To use it, you’ll need to enable Babel’s class properties transform.

But! If you’re using Create React App to bootstrap your projects, it already has the class properties transform turned on, and you can start using this class property syntax today.

Which is better? Constructor or no?

Like all things, it’s up to you.

Me, I prefer the clean look of the class property. I don’t like the extra boilerplate of the constructor, and having to remember to call super(props) (though ESlint can remind you to do that, and Create React App’s config does that out of the box).

You may have seen event handling functions being bound in the constructor, and might think constructors are required to pull this off. I’m talking about code like this:

class Thing extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(event) {
    // do stuff
  }
}

Another type of syntax supported by the class properties feature can make this constructor unnecessary: you can set a property equal to an arrow function, and the arrow function inherits the this binding of the class instance so you don’t have to bind it explicitly. It looks like this:

class Thing extends React.Component {
  // This is all you need to do:
  handleClick = (event) => {
    // do stuff
  }
}

This might look at little odd at first, but you can think of it this way:

// This statement:
const add = (a, b) => console.log(a + b);

// Can be thought of as assigning an arrow function to `add`:
const add = arrowFunction;

// where `arrowFunction` is expanded to:
(a, b) => console.log(a + b)

With that in mind, take another look at the class Thing example above. Hopefully it looks a little less weird. If you still hate it, give it some time and write some more arrow functions. I had the same problem at first. Your eyes will adjust :)

Learning React can be a struggle -- so many libraries and tools!
My advice? Ignore all of them :)
For a step-by-step approach, read my book Pure React.

Loved it! Very well written and put together. Love that you focused only on React. Wish I had stumbled onto your book first before I messed around with all those scary "boilerplate" projects.
— John Lyon-Smith
comments powered by Disqus