ES2015 Features Commonly Used with Functional Style React

Throwback post from 2015 from open.bekk.no.

Over the past few years ES2015 and React has seen wide adoption. Coupled with the easy access to build tools, ES2015 syntax has become the standard for many. This means that most examples of React (and related libraries) make heavy use of this new syntax. This can be confusing if you are not familiar with ES2015.

To help you make sense of and grok React examples written with heavy ES2015 use, I have compiled a list of examples of the most common ES2015 features used in a React setting. And especially in examples where React is used in a functional way. This will hopefully make the examples you read more clear and give some easy introduction to ES2015 along the way.

This post will focus on arrow functions, destructuring, enhanced object literals, and template strings, with some other features sprinkled in. Throughout the post, you can see asides. These are included as a nice to know points and information that are not necessarily directly related to the use of the specific feature. Asides are also used for giving additional information that is not strictly need to know, but some might find interesting.

After you have read this post, you will be ready to write all your functional style React applications using ES2015 with confidence. Without scratching your head wondering whats going on.

This post was originally posted on open.bekk.no back in 2015, but I think is just as relevant today.

Arrow Functions (aka fat-arrows)

The arrow function is one of the most widely used features in the latest iteration of the specification. One of the reasons it sees so much use, is that it’s much less verbose than normal function declarations. This means it fits better as arguments to other functions (also known as higher order functions).

var double = function (n) {
return n * 2;
};

// versus

var double = (n) => n * 2;
Aside: Anonymity
In ES2015 function names are inferred through the variable name (accessible with function.name). But a function declared with fat arrow syntax is always anonymous. This means you don't have a guarantee that a variable is bound to that function.
This brings trouble when you want to do recursive functions, as the variable outside the fat arrow can be changed. In recursive functions you would normally do
var myRecFunction = function myRecFunction () {
// inside here myRecFunction cannot be changed from outside the function.
}

In addition to brevity, fat-arrows offers lexical this. This means that if you use a fat-arrow in a function of an object literal, the context will the surrounding context (this) where the function is the defined. Arrow functions will be in the same context as the parent scope, and magic variables such as arguments will not be generated for function bodies in arrow functions.

Lexical this

var Component = React.createClass({
myOnClick() {
// Would work just fine, this is bound to the context of myOnClick
var log = (n) => console.log(this.refs[n]);
log('header');
log('subheader');
},

render () {
return <div onClick={this.myOnClick}>
<h1 ref="header">Hello</h1>
<h2 ref="subheader">World</h2>
</div>
}
});

No lexical this

var Component = React.createClass({
myOnClick() {
// Would NOT work, as this is not the component but the global object
var log = function (n) { console.log(this.refs[n]); }
log('header');
log('subheader');
},

render () {
return <div onClick={this.myOnClick}>
<h1 ref="header">Hello</h1>
<h2 ref="subheader">World</h2>
</div>
}
});

In the example of functions above, you would have to use closures and store this in a variable (for instance self), and use self.refs[n] instead.

Note: This change in context semantics is often a source of confusion. The context the function becomes bound to might not be what you expect if you use the fat arrow syntax mainly for its brevity. This typically occurs in object literals or when a function is passed as an argument to a callback or a higher order function. For instance:

// This will bind function to global object *not* the React class
var MyComponent = React.createClass({
render: () => {
// this.props will not be props to the React component, and the context most likely undefined
}
});

// Also binds the function (given as argument) to the global object.
// (this is a stateless function wrapped in some sort of decorating function
// for instance memoization or a "higher order component")
var MyComponent = component(() => {
// this.props will not be props to the React component, but probably undefined
});

You might want to consider using normal functions to be explicit about this, instead of saving a few characters by not having to type the function keyword.

Aside: Parentheses and Brackets
There are some gotchas using parentheses and brackets with fat-arrows. As a general rule, you have to use parentheses around parameters if there are more than one. There are also other rules if you use destructuring (see next section), or use it as arguments. Brackets must be used if the function body is more than one line or you want a “void function”. This flow chart from YDKJS will be of help.

You can read more about arrow functions on its MDN site

Destructuring

Destructuring is originally from the LISP world. You can extract values from objects without having to use multiple lines to do so. You can extract values from normal objects and arrays.

Example

// Only fetching some values from an array
var [a, , b] = [1, 2, 3];
console.log(a, b);
// => 1 3

// Combine with rest (accumulates the rest values)
var [a, ...b] = [1, 2, 3];
console.log(a, b);
//=> 1 [2, 3]

// Fetch from inside object
var {user: x} = {user: 5};
console.log(x);
// => 5

// Or as a shorthand
var {user} = {user: 5};
console.log(user);
// => 5
Aside: Rest values
The ...b syntax seen above is a separate ES2015 feature called rest. It takes a series of values and collects them into an array. This is particularly valuable for argument lists to avoid the automatic arguments bound variable (which is not created for fat-arrow functions), and for syntax based call and apply.
The counter part of rest, is spread. It converts an array to a argument list (series of values). See example below to understand better what it can be used for.
Example:
var someHigherOrderFn = function (fn) {
return (...args) => fn(...args); // spread.
}
// Instead of
var someHigherOrderFn = function (fn) {
return function myInnerFunction () {
return fn.apply(fn, arguments); // spread.
};
}
// As `arguments` isn't available for fat-arrows.
// this is invalid:
var someHigherOrderFn = function (fn) {
return () => fn.apply(fn, arguments);; // spread.
}

Example in React

Destructuring can be handy to have when fetching values from React props.

var Component = React.createClass({
render () {
// Get title and subtitle from props
var {title, subtitle} = this.props;
return <div>
<h1 ref="header">{title}</h1>
<h2 ref="subheader">{subtitle}</h2>
</div>
}
});
ReactDOM.render(<Component title="Hello" subtitle="World" />, el);

Example with Stateless Functions

// Destructuring in parameter position works the same as in variable declarations.
var Component = function ({title, subtitle}) {
return <div>
<h1 ref="header">{title}</h1>
<h2 ref="subheader">{subtitle}</h2>
</div>
};

ReactDOM.render(<Component title="Hello" subtitle="World" />, el);

See more examples of destructuring in this gist or read more about it on the MDN site.

Template Strings

Template strings is a small but sometimes very nice-to-have language addition that allows you to avoid using string concatenation. It also allows for string over multiple lines.

var someVariable = 42;
var myText = `
# Some markdown document
This is some longer text that extends over multiple lines.
Also it uses variables: ${someVariable}!
`;

Example in React

You might often end up doing string concatenation when defining CSS classes in your components. For example:

var Component = function ({title, subtitle, type}) {
return <div className={"namebox-" + type + "-container"}>
<h1 ref="header">{title}</h1>
<h2 ref="subheader">{subtitle}</h2>
</div>
};

This can be made more readable and easier to write using template literals:

var Component = function ({title, subtitle, type}) {
return <div className={`namebox-${type}-container`}>
<h1 ref="header">{title}</h1>
<h2 ref="subheader">{subtitle}</h2>
</div>
};

You can also do operations such as ternary inside a embedded expressions. But remember, this can hurt readability.

var Component = function ({title, subtitle, isSomeType}) {
return <div className={`namebox-${isSomeType ? 'type1' : 'type2'}-container`}>
<h1 ref="header">{title}</h1>
<h2 ref="subheader">{subtitle}</h2>
</div>
};

You can read more about template strings on its MDN site.

Enhanced Object Literals

In ES2015 we have gained two syntactic sugars when defining object literals: shorthand properties and shorthand methods (functions with a potential context).

Avoiding Redundant Text

You can save characters using enhanced object literals. Where as in pre-ES2015 you needed to duplicate property names and values, in ES2015, if the name is the same, you can avoid the redundant variable value.

var foo = 1;
// Before
var myObject = { foo: foo };
//> { foo: 1 }
// Now
var myObject = { foo };
//> { foo: 1 }

In many cases it might look like reverse destructuring, but it’s just a shorthand notation. Though, it goes very well in combination with destructuring.

For instance, the following code would work just fine.

var Component = function ({title, subtitle}) {
return <div>
<h1 ref="header">{title}</h1>
<h2 ref="subheader">{subtitle}</h2>
</div>
};
function render () {
var title = 'MyTitle';
var subtitle = 'Some silly text';
React.render(Component({title, subtitle}), el);
  // Instead of:
// React.render(Component({ title: title, subtitle: subtitle}), el);
}
render();

Short-hand methods

The shorthand from above also works on functions in object literals. For instance:

var MyComponent = React.createClass({
render() {
<h1 ref="header">Hello!</h1>
}
});
// instead of
var MyComponent = React.createClass({
render: function () {
<h1 ref="header">Hello!</h1>
}
});

Note, however, that this breaks “functions as expressions”. This means we can’t have the flexibility of treating functions as values in object literal declarations.

You can do:

// instead of
var MyComponent = React.createClass({
render: nullSafeData(function () {
<h1 ref="header">Hello!</h1>
})
});

But you can’t do:

var MyComponent = React.createClass({
nullSafeData(render() {
<h1 ref="header">Hello!</h1>
})
});

If you’re not a big user of decorators, or attaching additional function features by passing the original function as argument while declaring it, this might not be a big deal and can save you some typing. But if you, how ever, find that decorators and higher order functions is a valuable pattern, breaking this behaviour (“functions as expressions”) might be a high price to pay just to avoid the function keyword.

You can read more about the new object initialising syntactic sugar on MDN.

Closing notes

The hope is that you now should be able to read most of the functional React examples without having to worry about not understanding what component(() => 'hello'); does, what you get by doing function ({val}) or why var obj = {val} doesn't throw a syntax error.

There are several other features in ES2015 that can be useful for everyday React development. We have Proxies, Promises, modules and of course, a preferred choice of many: classes. But the ones above are the ones I find myself using regularly in functional React.

If you use some other ES2015 features with React that you feel this post is missing, a response or comment to this post, please feel free to post them in the comment section below or tweet me directly at @mikaelbrevik.

Like what you read? Give Mikael Brevik a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.