Well due to the wonderful work you’ve done on our recruitment scroll application The Reactionary Guild has seen an influx of Javascript wizards who are bringing new and even more powerful ECMAScript 2015 spells! In this tutorial we will add to our pipeline the ability for Babel to allow us to use the latest ES2015 (a.k.a ES6) syntax to build our scroll creation application, as well as explore the nuts and bolts of a few of them including import, export, destructuring and our first look at arrow functions.

Want to follow along but haven’t done the previous tutorials? Clone down this repo to give you a starting point. Once you’ve cloned it down run the command npm install in the root of the project and you’ll be good to go!

 

Bibbity-bobbity Babel!

Whilst ES6 has some really cool new features our ability to leverage these features in most modern browsers could be described as flaky at best. Not in the sense that browsers haven’t provided support for them outright but more in the fact that every browser, and indeed, almost every version of every browser has varying degrees of support for each of the available pieces of syntax in ES2015.

Anyway the point is that at the time of writing this article there is no way that any Web Developer in their right mind would write an application using pure ES6 in the hopes that every one of their users would only be using the one diamond in the rough of a browser that would support just the right features for their app to run. Instead Babel can fly in to save the day again!

So the first thing we will be doing is installing the ES2015 babel preset. This is so that when our .js and .jsx gets fed through webpack by our babel-loader and into babel then babel knows that we’re sending it ES6 code. Babel will then know that we want this code to be transpiled into javascript that is more browser friendly and ready to be shipped out and used by our users in their preferred modern browser.

Lets install the ES2015 preset. To do this we run the following command at the command line in the root of our project:

npm i babel-preset-es2015 -D

Now that we have the plugin installed we just need to let babel know that it’s available and that it should start using it. During the last tutorial we moved the babel settings into their own .babelrc file in the root of our project file. Open that up and add the "es2015" value to the presets array like so:

{
"presets": ["react", "es2015"],
"plugins": ["transform-react-jsx"]
}

 

How to conjure up your friends!

The first change that we will learn about is the way in which we take dependencies on other modules. We do this by using the import statement. Essentially the import statement is just a more explicit way of requiring in a module and assigning it to a variable. The functionality is not fundamentally changed but rather it’s just had some nice “housekeeping” features added.

The syntax for the import statement is:

import <variablename> from '<moduleName>'

where <variableName> is the name of the variable you want to assign the module to and <modulepath> is the path that you would have otherwise used if you were going to require the module in.

To try and help this explanation along let’s take a look at this in the context of our application. Open up ./src/script/CodeQuest.jsx so we can update the requires it uses.

See the two requires at the top of this file? We can refactor them to be import statements that, functionally, are exactly the same. We’re only going to refactor the react require for now though and we’ll remove the react dom require, you’ll see why later in the post. For now you can change the requires into imports like this:

import React from 'react';

 

Making your Javascript match your fashion sense…classy!

Another feature added in ES2015 was the ability to use classes. The class syntax is, once again, just a refinement on functionality that was effectively already supplied. But now it’s supplied in a much more explicit and terse format.

Where as in ES5 we would need to define classes and extend them using prototype syntax now with classes we can avoid some of the boiler plate code that we would have had to have to use to hook all this up. There are a number of changes to make to the code here so allow me to show you the entire updated codeQuest.jsx file and once you’ve had a moment to take it in I can walk through it with you.

import React from 'react';
class CodeQuest extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'Friend' };
this.handleChange = this.handleChange.bind(this);
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<div className="scroll">
<div>Hello {this.state.name}</div>
<div>I'd like to invite you on a wondrous adventure towards {'\r\n'} the grok of ReactJs. Will you join me?</div>
<div>Zac Braddy</div>
<div>The Reactionary</div>
</div>
</div>
);
}
handleChange(e) {
this.setState({name: e.target.value});
}
}

In this code snippet all the interesting changes are between lines 3 and 8. Let’s walk through each line and take about why they’re so interesting:

class CodeQuest extends React.Component {

What we have here is the declaration of our React component using class syntax. Previously we would assign the result of a call to React.createClass. But now we can define the class ourselves and inherit from React.Component to achieve the same result. We are inheriting from the React.Component class by using the extends syntax.

So previously our function call used to provide us with a prototype that could be used to construct CodeQuest elements, by using this new class syntax we get the same thing.

Moving on, you will see at lines four and five, the following code:

constructor(props) {
super(props);

Here we see the definition of the constructor for our new CodeQuest class. Because this class will get getting instantiated by the React framework we can expect a props object to be passed to our constructor and we should ensure that this gets passed down to our base class (remember that’s React.Component).

Now to complete our class we need to refactor out the definition we gave to the React methods for our component. Previously React.createClass created these for us on the class it was constructing but now we are building our own.

The first function we had was getInitialState. This function did what it said on the tin, so to provide the functionality in our new class we just need to intialise our state in the constructor of our new class. This is what is happening on line 6:

this.state = { name: 'Friend' };

The next function that we were defining previously was the render function. This goes almost entirely unchanged apart from the line that was declaring the function.

Whereas previously we were assigning a function the render key of the object we were passing in as a parameter to React.createClass we are now defining the render function on the class that we’ve created. You can see the changed line on line 10:

render() {

The function to be refactored is the handleChange method. This is a two part change. The first part is to do the same as we did to the render which is just change the definition of the function to define it as a method on the class rather than a property of the object being passed as a parameter to React.createClass.

The next thing we need to do is add a line in the constructor to rebind the handleChange method’s this property to point to the class itself. If we didn’t do this and handleChange was called as part of the change event on our textbox then the this property would be bound to the context of the handleChange function.

This would mean that when we called the this.setState function it would be undefined. By rebinding the handleChange function’s this property it will be able to access this.setState which is defined in the React.Component class.

class CodeQuest extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'Friend' };
this.handleChange = this.handleChange.bind(this);
handleChange(e) {
this.setState({name: e.target.value});
}

 

Level 5 separation of concerns spell!

I think you’ll agree that our code is beginning to look a lot more explicit and terse but there still an elephant in the room. We are defining our React component as well as taking care of rendering it to the DOM in the same file.

These are two things that we would really rather keep separate so that we can reuse our component if we so wish. Now you know the reason we removed the reference to ReactDOM earlier. So now we’re going to remove all the lines at the end of the codeQuest.jsx, the ones that make the function call to ReactDOM.render.

We are going to replace this with a single export statement. You can see the finished codeQuest.jsx file below with the change we need to make highlighted:

import React from 'react';
class CodeQuest extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'Friend' };
this.handleChange = this.handleChange.bind(this);
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<div className="scroll">
<div>Hello {this.state.name}</div>
<div>I'd like to invite you on a wondrous adventure towards {'\r\n'} the grok of ReactJs. Will you join me?</div>
<div>Zac Braddy</div>
<div>The Reactionary</div>
</div>
</div>
);
}
handleChange(e) {
this.setState({name: e.target.value});
}
}
export default CodeQuest;

The export statement is kind of the same story as the import syntax in that we’ve always been able to do the same, or similar things using a require statement. But now the export provides us with a standard for how to do things in a nice neat syntax.

When you put it in terms of a require statement an export statement is the equivalent of attaching a property to module.exports. So when someone imports your module they will be able to access the properties you have exported within your module definition.

If you are to use the default modifier like we have in the code above, this gives similar behaviour to if we were to assign directly module.exports a value directly. When someone required your module they would automatically get a copy of what you assigned to module.exports. In the same way if you use the default modifier anyone who imports your module without any modifiers will get what you exported by default.

There is a gotcha here though. Using the default modifier, under the hood, doesn’t just assign to module.exports it actually assigns to module.exports.default. This allows the ES6 code to give you the ability to have a default value that is returned when you import the module but also give you the ability to provide other properties that can be destructured off the same module. The downside to this is that if we require a module that has exported using the default modifier we must remember that the module that we would have gotten had we imported the module actually lives on the default property of the returned object rather than the returned object itself being the default property. We’ll see this later when we look at destructuring.

So now we have kicked our ReactDOM rendering out of it’s former home in the codeQuest.jsx we have to find a for it to live. It might not be the most appropriate place for it to live but for now the index.jsx will do.

We don’t have a index.js?! Well we will in a moment! Rename your index.js to index.jsx. Remember that this is the entry point for our application. We will have to tell webpack about this change or else it won’t know where to begin it’s work. Open up your webpack.config.js and make the change on the highlighted line below:

var path = require('path');
var config = {
context: path.resolve(__dirname + '/src'),
entry: './index.jsx',
output: {
filename: 'app.js',
path: path.resolve(__dirname + '/dist'),
},
devServer: {

Now we can head back to our newly renamed index.jsx and refactor it to bring in our CodeQuest component as well as the React modules that it needs:

import React from 'react';
import ReactDOM from 'react-dom';
import CodeQuest from './script/codeQuest.jsx';
require('./script/codeQuest');
require('./css/codeQuest.css');
require('./index.html');
ReactDOM.render(
<CodeQuest />,
document.getElementById('the-kingdom')
);

And that’s it. This is all we need to make the code work again. You should be able to execute the command npm start in the root of the project and everything should work as it has in all the previous tutorials

 

Breaking things down

I’d like to take a moment to show you a couple of other cool features that are available to us in ES6. Now I’ll begin by saying that I know, and I agree, that in our small app these features might be a little bit overkill but I’d like to demonstrate them for you because it doesn’t take a lot of complexity in your code before you start benefiting from these enhancements. The first thing I’d like to show is the syntax for destructuring an object.

Destructuring an object is syntactic sugar that allows you to take a property on an object and assign a copy of it to a local variable. You can do all of this with desctructuring all in one statement!

This becomes handy when you want to access a number of properties on an object without having to refer back to the object in every place you want to use these properties, say for instance the props object of your component. In the example below we have simply destructured the this object and state objects so that we don’t have to refer to the this object in our JSX.

render() {
const { handleChange, scrollData } = this;
const { name } = this.state;
return (
<div>
<input type="text" onChange={handleChange} />
<div className="scroll">
<div>Hello {name}</div>

You can see here that line 17 is the equivalent of declaring two variables called handleChange and scrollData respectively and then assigning each of them the appropriate values from the equivalent properties on this.

Another thing that you can destructure is modules themselves, they are only objects after all. So for example we could destructure the Component class out of the React module so that we don’t have to refer to the React object when we are inheriting from the Component class in our own, like this:

import React, { Component } from 'react';
class CodeQuest extends Component {

Destructuring, as you can see, is a very valuable tool that allows use to write highly readable and thus maintainable code.

 

B-B-B-Bonus Spell!

The last thing I’ll show you in this post is the use of arrow functions. Arrow functions are a much more terse way of defining a function.

The syntax reads a lot the same way as a C# Lambda expression in that that you just define your parameters either between parenthesis if you have 0 or many parameters or you can use no parenthesis if you only have a single parameter to declare. You then follow your parameters with the => operator and then the body of your function between curly braces.

Now because in javascript functions are already objects we could already pass them around in parameters and so forth. So arrow functions don’t quite open up the same expanse of new opportunities that Lambda’s did for C#. But it does mean that you no longer have to type the keyword function or sprinkle parenthesis throughout your code to ensure you get the desired effect. This added functionality is definitely a welcome addition but it is more of a housekeeping thing in our code than anything else.

To give you an example of using arrow functions and to prepare our codebase for future improvements let’s refactor out the message that is included in our scroll invitation. We will put the message into an array which we can then wrap with divs using the javascript array’s map function. Below is the complete and final code for the codeQuest.jsx for this week. I’ve highlighted the changes necessary for this refactor and we can walk through them after you’ve had a moment to digest them.

import React, { Component } from 'react';
class CodeQuest extends Component {
constructor(props) {
super(props);
this.state = { name: 'Friend' };
this.handleChange = this.handleChange.bind(this);
this.scrollData = [
'I\'d like to invite you on a wondrous adventure towards \r\n the grok of ReactJs. Will you join me?',
'Zac Braddy',
'The Reactionary',
];
}
render() {
const { handleChange, scrollData } = this;
const { name } = this.state;
return (
<div>
<input type="text" onChange={handleChange} />
<div className="scroll">
<div>Hello {name}</div>
{
scrollData.map(textItem => {
return (<div>{textItem}</div>);
})
}
</div>
</div>
);
}
handleChange(e) {
this.setState({name: e.target.value});
}
}
export default CodeQuest;

The map function iterates over each of the items in the array and replaces the value in the array with the value returned by the function that you give map as it’s first parameter.

You can see here we are supplying map it’s first parameter by defining an arrow function. Within our arrow function we are defining a single parameter which we are calling textItem. For each item in the array map will call this function that we’ve given it and pass the current element into the textItem parameter.

Our arrow function then returns the value that was passed in wrapped in a JSX div tag. You can see that we have all this code wrapped in curly braces within our JSX which means the resulting array will be evaluated out into the JSX we are returning from render. If you now execute npm start again you will find that all of this will worked and the application is back to the way it always has been.

 

Till next time

Unfortunately, this week we have not done a lot in terms of functionality for the app but sometimes that’s par for the course with development. We have learned a lot about some of the latest tools we can use to create great apps though and in the coming tutorials I hope that we can grow our demo app and I can show you some of the other cool spells you can cast with React!

The good news is that whilst we didn’t add a lot in terms of functionality we are closer than ever to producing code that you would (and will) see out there in the wild. Certainly techniques like arrow functions, classes and destructuring are all things that I would encourage you to include in your own code to make it easier to read and maintain.

If you’d like to learn more about the things that ES2015 has to offer a good starting place is over at Babel. See you next time Code-venturer!