loading...

Modernize your ReactJS application with async/await in 2018

codeprototype profile image Kevin Le ・1 min read

To start 2018, you can modernize your ReactJS application by incorporating the async/await feature. Assume you already use a Promise-based HTTP client library such as axios, you can easily refactor your existing code, or you can just start using async/await in new codes.

Either way or both, here's a small snippet that can help:

import axios from 'axios';
...
class Login extends Component {
    constructor(props, context) {
        super(props, context);
        this.onLogin = this.onLogin.bind(this);
        ...
    }
    async onLogin() {
        const { email, password } = this.state;
        try {
            const response = await axios.post('/login', { email, password });
            console.log(response);
        } catch (err) {
            //handle error
        }
    }
    ...
}

So the code change is very minimal. But running webpack might result in an error. The error might say something like regeneratorRuntime is not defined. In that case, it's a simple fix:

npm install babel-plugin-transform-runtime --save-dev

Then in the .babelrc file, simply add

{
    ...
    "plugins": [
        ["transform-runtime", {
            "regenerator": true
        }]
    ]
}

Other than adding babel-plugin-transform-runtime and a simple modification to the .babelrc file, no babel-runtime, no polyfill is necessary.

Posted on Dec 31 '17 by:

codeprototype profile

Kevin Le

@codeprototype

Driven by passion and patience

Discussion

markdown guide
 

Did you have a look at the transpiled JS code?

While async/await is a great feature, the size of the transpiled code is enormous.

The simple onLogin method of your example gets transpiled to this:

var onLogin = function () {
    var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
        var _state, email, password, response;

        return regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
                switch (_context.prev = _context.next) {
                    case 0:
                        _state = undefined.state, email = _state.email, password = _state.password;
                        _context.prev = 1;
                        _context.next = 4;
                        return axios.post('/login', { email: email, password: password });

                    case 4:
                        response = _context.sent;

                        console.log(response);
                        _context.next = 10;
                        break;

                    case 8:
                        _context.prev = 8;
                        _context.t0 = _context['catch'](1);

                    case 10:
                    case 'end':
                        return _context.stop();
                }
            }
        }, _callee, undefined, [[1, 8]]);
    }));

    return function onLogin() {
        return _ref.apply(this, arguments);
    };
}();

So before using async/await, one should ask if the increased code size is acceptable.

 

It's good to have an eye on the transpiled code. For a simple case, it might seem like there's no gain of using async/await over using then clauses. But the benefits of using async/await will be more obvious when the business logic gets more complicated. Async/await code will be more readable than "then" clauses.

Now if you have to stop each time to compare the size of the transpiled code, then I recommend against that. I also recommend against coming up with a rule that says something like "Ok, less than 2 "then" clauses, then no async/await".
Business logic does change. So suddenly we have to make one more asynchronous call, then such rule is more trouble than it's worth.

 

It depends what browsers you're targeting. Assuming (and I hope) you use babel-preset-env, async/await will only be transpiled to ES5 for pretty much just IE11 and below. All the other browsers support await now.

If most of your market is IE <= 11 , then maybe perhaps it's not wise to use async/await. Honestly though so many things come in to play for bundle size, but obviously a smaller bundle size is usually a good thing.

This is great news! Since it's ES7 I assumed it won't be implemented by browsers yet.

Thanks for pointing out that it is.

Regarding the bundle size, I agree that many things affect that. But I don't think that bloating up async/await statements to 10x the original code size is negligible.