Click here to Skip to main content
15,881,715 members
Articles / Web Development / React

Where to Initialize State in React

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
27 May 2018CPOL4 min read 5.6K   2   1
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?

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
  }
}

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

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

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

This article was originally posted at https://daveceddia.com/feed.xml

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Dave is a Software Engineer in the Boston area and writes about AngularJS and other JavaScript things over at daveceddia.com

Comments and Discussions

 
QuestionTags Pin
Rick York1-Jun-18 6:40
mveRick York1-Jun-18 6:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.