Enabling optional chaining in a create-react-app

Update: This article contains outdated information. Use create-react-app version 3.3.0 or upgrade to react-scripts 3.3.0 or above instead of doing all the stuff below.

On December 4th 2019, create-react-app v3.3.0 was released. This version includes the Optional Chaining and Nullish Coalescing Operators.

On January 11th 2020, Babel 7.8.0 was released. This new version of Babel includes the nullish coalescing (??) and optional chaining (?.) with preset-env.

In this post, we’ll learn how to enable optional chaining in an application created using create-react-app. This is probably not something that should be done for a production application, actually I would actively encourage against doing that, but on July 25th, optional chaining was moved to stage 3 proposal, and this is just a fun exercise to see what the buzz is all about.

Before going further, let’s explain what optional chaining is.

Usually when dealing with nested objects, developers need to test for the existence of every property, which can make code look like this:

let nestedProp = obj.first && obj.first.second;

This quickly becomes cumbersome and quite ugly. I’ve seen other solutions, that are not much better. This one attempts to provide a default value:

let nestedProp = (obj.first || {second:'Default value'}).second;

Convenience libraries like lodash have also provided ways to deal with this, which just results in a multitude of solutions for a seemingly easy problem to solve, and a problem that has been solved in many other languages.

The Optional Chaining operator allows to rewrite the code above:

let nestedProp = obj.first?.second;

And that’s it. No boolean logic, no convenience function, no trying to find a clever solution for a simple problem.

Now let’s see how we can use that to our advantage.

First let’s create a new react app:

$ yarn create react-app optional-chaining-demo
$ cd optional-chaining-demo

By default, a new create-react-app does not support this language feature, so we need to use a babel plugin to make this available. By default, create-react-app does not allow modifying the babel configuration of the project, so we’ll need to install two additional modules that allow supplementing the default configuration, and the babel plugin that enables the new operator:

$ yarn add customize-cra react-app-rewired -D
$ yarn add @babel/plugin-proposal-optional-chaining -D

To enable the configuration override, just create a new config-overrides.js file at the root of the project.

// config-overrides.js
const { useBabelRc, override } = require('customize-cra');
module.exports = override(useBabelRc());

And enable the babel plugin, in a new .babelrc file:

// .babelrc
{
"plugins": ["@babel/plugin-proposal-optional-chaining"]
}

Finally, we need to modify the package.json scripts section a little bit so our new config and babel plugin are picked up. Just remove the scripts section and replace it with the one below:

"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom"
},

That’s it for the plumbing, when running yarn start, the application should start gracefully.

Now how can we use this new optional chaining operator?

Let’s create a simple component named Demo.

const Demo = ({ nestedProp }) => (
<>{nestedProp.first?.second}</>
);

And simply call it as any other component:

// Displays hello world
<Demo nestedProp={{ first: { second: 'hello world' } }} />
// Does not display anything
<Demo nestedProp={{ first: {} }} />

Without the optional chaining operator, the Demo component would have needed some sort of conditional check, like this:

const Demo = ({ nestedProp }) => (
<>{nestedProp.first ? nestedProp.first.second : ''}</>
);

Or this:

const Demo = ({ nestedProp }) => (
<>{nestedProp.first && nestedProp.first.second}</>
);

The code is a little terser, a little easier to read, and a little better. That’s a win!

It’s too early to know if this will become a widespread style in the React community, or what best practices will emerge, but I thought it would be interesting to have a look. Feel free to use this code and test other new language proposals using it, and let me know if you do!

The code is available on github.

Previously Paris and Geneva, currently New York. Can also be found at https://dev.to/arnaud

Previously Paris and Geneva, currently New York. Can also be found at https://dev.to/arnaud