DEV Community

Dave Ceddia
Dave Ceddia

Posted on • Originally published at daveceddia.com on

Where to Initialize State in React

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"
      someDefaultThing: this.props.whatever
    }
  }

  render() {
    // whatever you like
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

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);
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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 :)

Where to Initialize State in React was originally published by Dave Ceddia at Dave Ceddia on March 29, 2018.

CodeProject

Top comments (3)

Collapse
 
vikrantnegi profile image
Vikrant Negi

After google for many hours I find the explanantion here. Thanks.

Collapse
 
dceddia profile image
Dave Ceddia

Glad it helped! Makes me wonder if I should change the title to help people find it easier though. What were you searching for?

Collapse
 
vikrantnegi profile image
Vikrant Negi

I googled for "Difference between State in constructor vs state without a constructor".