react christmas

Class property initializers

←Previous postNext post →

Although not React specific, this technique has made our React code much simpler and easier to read. Say hello to class property initializers!

A 3 min read written by
Kristofer Selbekk

Usually, when you create a class-based React component, you end up with something like this at the top:

class MyComponent extends React.Component {
  constructor() {
    super();

    this.state = {
      isClicked: false,
      isHovering: false,
    };

    this.onClick = this.onClick.bind(this);
    this.onMouseEnter = this.onMouseEnter.bind(this);
    this.onMouseLeave = this.onMouseLeave.bind(this);
  }

  onClick() {...}
  onMouseEnter() {...}
  onMouseLeave() {...}
}

Whenever you have state and/or callbacks like above, the constructor gets tons of this boilerplate code that does nothing but confuse beginners and people new to your codebase. What if I told you there was a way to remove the constructor completely?

Hi there, class property initializers!

The TC39 standards committee - the people in charge of specifying new features in JavaScript - are now looking into a proposal for a new language feature called class property initializers. That proposal basically lets you initialize your state tree, and it lets you use arrow functions to avoid binding callbacks! This is how the code above would look with this new language feature:

class MyComponent extends React.Component {
  state = {
    isClicked: false,
    isHovering: false,
  };

  onClick = () => { ... }
  onMouseEnter = () => { ... }
  onMouseLeave = () => { ... }
}

See? There's no constructor anymore!

Upsides a-plenty!

Although the two examples above are functionally equivalent, I think the latter has a few very great upsides.

First of all, you don't have to specify a constructor. That means you don't have a constructor to stuff other things into, and it's easier to do the right thing and use lifecycle methods instead. I've made several hard-to-track-down bugs this way the last couple of years, mostly because the way the constructor works is a bit counter-intuitive (it's called whenever the component is rendered, not declared) and hard to understand - especially for beginners.

A second huge benefit is that you have to write less boilerplate to create class based components. You don't have to remember to bind callback methods (also a huge source of weird bugs), and you don't have tons of code "just because you have to."

Finally, you can specify propTypes and defaultProps fields inside the class definition instead of adding them at the bottom of the component file. This lets you define the interface of your component at the top of the file, which again makes it easier to use your component for future consumers. Since they are static properties, they have to be prefixed with the static keyword:

class MyComponent extends React.Component {
  static propTypes = {
    heading: string.isRequired,
    onClick: func,
  };

  {/* Rest of component */}
}

Not perfect

Although I'm personally a huge fan of this pattern, I know many are not. This is especially true when it comes to using arrow functions to declare callbacks. Some people argue that this is a misuse of the specification, and that it makes the this context very uncertain.

To be honest, this is something you and your team need to discuss before you start using it. In my current team, we're only using this technique for specifying state and prop types - which is a huge improvement nonetheless.

Either way - I hope you give these a try!

←Previous postNext post →