Should I use React.createClass, ES6 Classes or stateless functional components?

So you’ve decided to build a React component. You know what it will do, what it’s called, and where it’ll go. But when you open your editor and go to write the first line, you’re confronted with the decision between three different ways to declare it? Why three? And which one should you use?

Luckily, this decision doesn’t need to be a hindrance. In fact, with a little history and two simple rules, it’ll only take a few seconds to get on with the job of writing your component. And without further adieu, here’s the first rule:

Rule 1: If your component needs to access this, use ES6 Classes

Stateless functions don’t have a this object; if you need anything defined on this other than props, you’ll need a component class.

But this.state and this.refs are important parts of many useful React components. Isn’t it a little weird to have this limitation?

Why don’t stateless functional components have this?

As you may know, JSX tags compile to plain old JavaScript objects — not HTML.

Let’s take a <div /> tag for example. Passing it to the JSX compiler will return this JavaScript:

React.createElement('div')

And as React’s documentation shows, this just returns a ReactElement – i.e. a plain JavaScript object. The structure of this ReactElement looks something like this:

{ type: 'div', props: {}, ref: null, key: null }

But this presents an interesting problem; if each call to your component’s render function produces a new object, how is it that its this object continues to contain the same state and refs between renders? Indeed, how is it that a plain old JavaScript object is connected to the DOM at all?

React Elements and Class Instances

Ok, I was being a little tricky above. I purposefully omitted an important step.

Remember that when you create a ReactElement with a JSX <div />, it isn’t connected to the DOM. It isn’t until you call ReactDOM.render on an element that it and its children are rendered to the DOM. But creating DOM nodes is not all that ReactDOM.render does – it also creates ReactComponent instances.

But what are these ReactComponent instances? Think about it this way: if a ReactElement is an instruction to React that you need an instance of your component, a ReactComponent is the actual component. Or to put it another way, rendering a ReactElement lets React know that we need a ReactComponent.

Let’s check your understanding with a quick quiz. Given the above explanation, do you know what type of object your component’s this is? Touch or hover your mouse over the box below to check your answer:

this is a ReactComponent instance. Each ReactComponent holds state, refs, etc.

Stateless Functional Components

But stateless functional components aren’t classes – they’re functions. They don’t have a persistent this property to attach a ReactComponent instance to. But while a this object expands a component’s possibilities, it also has a cost: keeping a ReactComponent linked up with its ReactElement objects takes work.

By using stateless functional components, you’re signalling to React that you don’t need that ReactComponent. From this, it is able to make a bunch of optimisations — which while currently modest, are set to grow. But even before these performance improvements materialise, there are a number of things your components won’t have to do if they’re classless. Which brings us to the second rule.

Rule 2: If your components need lifecycle methods, use ES6 classes

Without a common this property, stateless functional components wouldn’t be able to communicate with their lifecycle methods. As a result, React doesn’t provide them. And as this enlightening comment in the React codebase shows, this can save a lot of work:

/**
 * ------------------ The Life-Cycle of a Composite Component ------------------
 *
 * - constructor: Initialization of state. The instance is now retained.
 *   - componentWillMount
 *   - render
 *   - [children's constructors]
 *     - [children's componentWillMount and render]
 *     - [children's componentDidMount]
 *     - componentDidMount
 *
 *       Update Phases:
 *       - componentWillReceiveProps (only called if parent updated)
 *       - shouldComponentUpdate
 *         - componentWillUpdate
 *           - render
 *           - [children's constructors or receive props phases]
 *         - componentDidUpdate
 *
 *     - componentWillUnmount
 *     - [children's componentWillUnmount]
 *   - [children destroyed]
 * - (destroyed): The instance is now blank, released by React and ready for GC.
 *
 * -----------------------------------------------------------------------------
 */

You may have noticed that the above two rules have something in common: they’re both about the situations in which stateless functional components can’t be used. As a result, you don’t even really need two rules; they could be merged into one:

Golden Rule: If you can use a Stateless Functional Component, then do so.

Of course, sometimes you can’t use a stateless functional component. In these cases, I recommend React.Component over React.createClass. And to find out why, let’s learn a little history.

A little history

As you probably already know, React didn’t have stateless functional components until quite recently. In a way, this helps to explain why you’d want to use them when possible — they wouldn’t have been added unless there was a clear reason to do so.

You also may know that React.Component is a relatively recent addition to React. This gives you a clue as to why it’d be preferred over React.createClass. For another clue, look at the naming of their respective locations in the React repository — modern vs. classic.

But more concretely, React.Component has a much smaller API than React.createClass.

A smaller, equally powerful API

Where React.createClass has mixins, ES6 Classes are well suited to Higher Order Components. While these may feel unfamiliar at first, they’ll soon feel far more natural than the alternative. HOCs give you more power than mixins in a more intuitive package. And the fact that a HOC is just vanilla JavaScript means that you don’t have to worry about them being deprecated.

Similarly, where React.createClass has auto-binding of function methods, Babel and ES6 Classes let you bind only the required methods. This improves performance, while again decreasing the probability of your code being deprecated.


And with that, you now have the tools you need to choose how to define your components. In summary:

  • If you can use stateless functional components, do so
  • Otherwise, use ES6 Classes

But while this will get you over the first hump, there are many more decisions you’ll need to make. For a start, how are you going to style your new component? Will you use inline style, CSS Modules, or maybe Pacomo? And even once you’ve got your styles sorted, do you know how you’ll store your component’s state? Will use use setState, Redux, or maybe something else?

Now you could find this all out the hard way: with Google and trial and error. Or, you could just join my Newsletter — next month I’ll be sending out a decision chart covering styling, flux, build systems, and more. Of course, it will be exclusive to subscribers.

And to sweeten the deal, in return for your e-mail you’ll immediately receive three print-optimised PDF cheatsheets. One on React (see preview), another for ES6 and yet another for JavaScript promises. All for free!

I will send you useful articles, cheatsheets and code.

I won't send you useless inbox filler. No spam, ever.
Unsubscribe at any time.

One more thing – I love hearing your questions, offers and opinions. If you have something to say, leave a comment or send me an e-mail at james@jamesknelson.com. I’m looking forward to hearing from you!

Read More

15 Comments Should I use React.createClass, ES6 Classes or stateless functional components?

    1. James K Nelson

      I’m not sure what you mean by “be careful to use this mixin when using classes”? It seems to me like a bad idea to add a shallow equals comparison to all classes unless you need the performance improvement.

      See this GitHub issue on the React repository for more reading – shouldComponentUpdate is more meant as an escape hatch for performance improvements than something which necessarily must be implemented on every component.

      Reply
  1. Alberto Velandia

    Great post, when you say: ” if a ReactElement is an instruction to React” didn’t you mean, ” if React.createElement is an instruction” ?

    Reply
    1. James K Nelson

      While its true that React.createElement is an instruction in a way, all it does is return a plain object (i.e. a ReactElement). Passing that ReactElement to ReactDOM.render is what actually creates the ReactComponent. So, you can think of the ReactElement as the instruction which is passed to ReactDOM.render.

      Reply
  2. Tom

    “if you need anything defined on `this` other than `props`, you’ll need a component class.”

    `context` is also supplied to a stateless functional component in the 2nd argument.

    Reply
  3. Roman

    I don’t see a reason why one should use ES2015 class components over React.createClass. Both are well suited to use with HOCs, that’s the beauty of HOCs, not of classes.

    I’m not against class components, but I don’t see here a real reason which explains why I must use classes instead of React.createClass. I personally prefer the latter, because it’s just a function call and I don’t want to bring new entities into the code if there’s no real benefit of using them.

    Reply
  4. Andrea

    Hey James, thanks for your great article! Helped a lot seeing through the mess. As a beginner in the react world and in the modern web area I could say (I remember like 7 years ago, choosing your tools was easier as we didn’t have that many options), I am having a hard time making choices which is impacting my mood haha
    Thanks again!

    Reply

Leave a Reply

Your email address will not be published.