Convert React.createClass to ES6 Class

By Dave Ceddia

As of React 15.5, createClass is deprecated. You’ll get warnings in the console if you’re using it in your code – and, when React 16 comes out, createClass will be removed entirely.

What to do? Well, update your code, of course!

This video and article go over how to convert to ES6 classes. You also might want to know how to convert to stateless function components and I’ve got a video and article for that as well.

Refactor createClass to ES6 Classes

Replace createClass

When replacing React.createClass there are 2 options:

Here’s how to decide:

  • Use an ES6 class if either:
    • the component uses state (search for “this.state” to make sure)
    • the component uses lifecycle methods like componentDidUpdate, componentDidMount, etc.
    • the component has handler methods (handleClick and such)
  • Use a stateless function if none of the above is true

This post covers converting to ES6 classes – another one covers stateless functions.

Before: createClass

import React from 'react';

var InputControl = React.createClass({
  propTypes: {
    initialValue: React.PropTypes.string
  },
  componentDidMount: function() {
    console.log('mounted');
  },
  getDefaultProps: function() {
    return {
      initialValue: ''
    };
  }},
  getInitialState: function() {
    return {
      text: this.props.initialValue || 'placeholder'
    };
  },
  handleChange: function(event) {
    this.setState({
      text: event.target.value
    });
  },
  render: function() {
    return (
      <div>
        Type something:
        <input onChange={this.handleChange}
               value={this.state.text} />
      </div>
    );
  }
});

After: ES6 Class

import React from 'react';

// PropTypes is a separate package now:
import PropTypes from 'prop-types';

// replace React.createClass with a class:
class InputControl extends React.Component {
  // Use static properties for propTypes/defaultProps
  static propTypes = {
    initialValue: PropTypes.string
  }

  static defaultProps = {
    initialValue: ''
  }

  // Initialize state right in the class body,
  // with a property initializer:
  state = {
    text: this.props.initialValue || 'placeholder'
  }

  // Use an arrow function to preserve the "this" binding
  // without having to bind in the constructor, or in render.
  handleChange = (event) => {
    this.setState({
      text: event.target.value
    });
  }

  // In classes, functions are written without
  // the 'function' keyword. Also, notice there are no commas
  // between properties
  render() {
    return (
      <div>
        Type something:
        <input onChange={this.handleChange}
               value={this.state.text} />
      </div>
    );
  }
}

What changed?

  • Properties in the class don’t have commas between them, like they do in plain objects.
  • Functions are written without the “function” keyword.
  • Arrow functions are used for member functions that need to preserve the this binding.
  • State is initialized with an assignment (“property initializer”) rather than having to implement a function to return it.
  • PropTypes is no longer under React, so React.PropTypes is replaced by PropTypes.
  • propTypes and defaultProps are set as static properties instead of functions, though they can still be set outside the class too, like InputControl.propTypes = { ... }.

Example Project

I put together an example project with 7 different components, both before and after conversion, including the codemod-generated version.createClass to stateless functions. You can download it here (no email required).

Automate It!

The helpful folks at Facebook created a project called react-codemod which holds a suite of scripts for automatically transforming old-and-busted React code into the modern style.

Right now it contains 11 different scripts to transform all kinds of things, like changing React.PropTypes to PropTypes, converting createClass to ES6 classes, and even sorting the methods in a component to match best practices. You can see the full list in the repo but we’ll go over how to apply the createClass -> ES6 transform here.

Straight from the repo, the instructions are:

  • npm install -g jscodeshift (or yarn global add jscodeshift)
  • git clone https://github.com/reactjs/react-codemod.git
  • Run npm install (or yarn) in the react-codemod directory
  • Run jscodeshift -t <codemod-script> <path>
    • codemod scripts are under react-codemod/transforms, and <path> should point to a file (or multiple files) in your source code.

The jscodeshift tool can take the the -d option for a dry-run (print what would be done, but don’t make changes) and the -p to print the output for comparison.

Here’s the command to transform createClass to ES6 (it’s long, I know):

jscodeshift -t react-codemod/transforms/class.js --mixin-module-name=react-addons-pure-render-mixin --flow=true --pure-component=true --remove-runtime-proptypes=false <path>

It did a nice job on the test file I passed through it. My results are included with the example project, which you can download here.