Babel’s Transform Class Properties Plugin: How it Works and What it Means for your React Apps

Jacob Worrel
Oct 12, 2017 · 6 min read

Today we’re going to explore a neat little Babel trick that’ll help you clean up your React code in a big way.

Babel

Babel is a powerful tool for writing next generation JavaScript. It’s widely used to compile code written with newer and experimental JavaScript features (as well as JSX in React apps) into syntax browsers can understand.

Developers no longer need to wait for recently added features to get adopted by browsers or for promising new features to go through the lengthy TC39 process, where each proposal must get approved to move through various stages before finally getting added to the next ECMAScript spec. Thanks to a whole host of Babel presets and plugins, we can now write the JavaScript of tomorrow, today.

In this post, we’ll go over a particularly useful Babel plugin for your React apps and how you can use it to write cleaner, more concise code.

Class Properties Transform

If you’ve ever written a React app, you may have seen something along the lines of:

constructor(props) {
super(props);
this.state = { ...some initial state... }

this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
}

Whoa! That’s a lot of handlers.*

And what a drag it is to have to individually bind the this context to each of them just so they can be passed down as props and invoked somewhere further down the component tree. How many times have you forgotten to do this tedious task and gotten an error message saying “this.setState is not a function”? How many times have you looked at a piece of code like the one above and thought to yourself, “There’s gotta be a better way…”

Well, guess what? There is, thanks to Babel’s Class Properties Transform plugin…

According to the documentation, this plugin will transform class properties in such a way that you can define class properties using property initializer syntax (ie. by using the = assignment operator).

In JavaScript, current class syntax only allows for you to define methods inside of a class, nothing else.

class Cat {
constructor(name, breed) {
this.name = name;
this.breed = breed;
}
getBreed() {
return this.name + ' is a ' + this.breed;
}
}

Any properties you want on an instance of an object created with a class need to be defined inside of the special constructor method, whereas any other methods defined in the class — like the getBreed() method in the example above — will live on that instance’s prototype.

But with Babel’s Class Properties Transform plugin, you no longer have to follow these rules, and instead can do something like this:

class Cat {
name = "Chairman Meow";
breed = "Sphynx";

getBreed = function() {
return this.name + ' is a ' + this.breed;
}
}

In this version, the ‘name’ and ‘breed’ properties as well as the getBreed() method will live on the instance, whereas before getBreed() was on the prototype.

So how does this tie into React and not having to bind the this context to every handler I want to pass down as a prop?

Well, because the = assignment operator won’t throw a syntax error anymore, what this allows you to do is write methods inside of an ES6 class using fat arrow notation. And since arrow functions do not create their own this and use the value of the enclosing context instead, you no longer have to slavishly bind the this context to every method you define inside your React component. (If you haven’t read my post about ES6 arrow functions, I recommend that you check it out to better understand where they should and shouldn’t be used.)

So with that said, we can now refactor our Cat class to look like this:

class Cat {
name = "Chairman Meow";
breed = "Sphynx";

getBreed = () => {
return this.name + ' is a ' + this.breed;
}
}

…and BOOM! The this context inside of the getBreed() method will always point to the appropriate instance of the Cat class.

Using Babel’s Transform Class Properties Plugin in Your React Apps

So let’s imagine we’re building a simple React app that renders a bunch of cats, and when a user clicks on a cat, it will show an alert with a static message saying, “Hi there! I’m so cute and cuddly!”

The first thing we’ll need to do is create a container component where we’ll store all the state we’ll need (in this case, just an array of image urls and a string containing our static message). This component will handle rendering our individual Cat components as well as our business logic (ie. alerting the user of the message).

import React, { Component } from 'react';
import Cat from './Cat';
export default class CatContainer extends Component {
constructor(props) {
super(props);
this.state = {
cats: [
'http://www.catphotos.org/wp-content/uploads/2013/02/cat-standing.jpg',
'http://www.catphotos.org/wp-content/uploads/2013/02/a-serious-1024x768.jpg',
'http://www.catphotos.org/wp-content/uploads/2013/02/white-cat-1-1024x768.jpg'
],
msg: "Hi there! I'm so cute and cuddly!"
}
}
showMessage = () => {
alert(this.state.msg);
}
render() {
const cats = this.state.cats.map(url => (
<Cat url={url} showMessage={this.showMessage}/>
));
return (
<div>
{cats}
</div>
)
}
}

Notice how I’m writing the showMessage() handler as an arrow function, and therefore don’t need to bind the this context to it inside of my constructor. It just uses the value of its enclosing context, which in this case points to the CatContainer.

Now, all we need is our Cat component. Since all this component does is render JSX, we’ll go ahead and write it as a stateless functional component:

import React from 'react';const Cat = (props) => {
return (
<div>
<img src={props.url} onClick={props.showMessage}/>
</div>
)
}
export default Cat;

And now, when we click on a cat, our alert shows up as expected. Not, a TypeError saying “cannot read property ‘state’ of undefined”, just a nice little message from our cute and cuddly cat.

The Class Properties Transform is just one of many Babel plugins you can use to leverage the power of bleeding-edge JavaScript features. Another one I always throw into my .babelrc file for good measure is the Object Spread Rest Transform (especially if I’m using Redux and writing lots of logic to reduce an old state object into a new state). At a recent talk given by @krainboltgreene, I was introduced to the Babel React Optimize preset, which basically parses your React code and implements a bunch of ways to optimize it (without you having to lift a finger).

JavaScript is evolving and tools like Babel are an essential tool for keeping up with the rapid rate of change. If you haven’t already incorporated Babel into your developer workflow, play around with their suite of presets/plugins and see how it can help you write better, more modern code.

*******************************************************************

*If you have this many handlers inside one component, you probably want to rethink how you’re designing your component hierarchy. You could try implementing the container pattern, like I’m doing in the cat app example above. This pattern makes use of container components (aka ‘smart’ components) at various levels of the app to handle your business logic. All your other components can then be written as stateless functional components (aka ‘presentational’ or ‘dumb’ components that are strictly concerned with rendering JSX). In conjunction with a state management library like Redux, this is a powerful way of writing maintainable code with a strong separation of concerns.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade