Home

Components With Async Friendly Event Handlers

Posted on May 26, 2021


All apps have to listen to user input, it could be a button click or some text being typed in an input box. These user actions in return perform a task like api call, validating the input, etc. These actions can be asynchronous in nature and it's in these cases where having async event handlers is quite beneficial.

Let's take a simple example of a button. On clicking the button, we'll make an api call and then render an image from the api's response. I'll be using React here but these ideas remain same for other frameworks too.

As you can try in the above example it works perfectly well. But what if it's an expensive api call (time consuming) or if the user is on a bad network? There are a few issues with this scenario. Let's look at them one by one:

Writing Components With Async Event Handler

Let's look at the same example but this time implemented with async onClick handler.

What did we change? We made the onClick function passed to button async function which resolves after the response from the api call. We also added a Button component which has it's own internal state which enables the button or shows the 'loading' state. The Button component can internally change this state based on when it's clicked and when the onClick handler resolves.

Benefits Of Using Async Event Handler

Here we considered a button component but, this same logic can be extending to all forms of input components.

Imagine you have a input box with some async validations. How nice it'd be, if the input component can update it's state (show user the validation error) based on whether the async onChange is resolved or rejected. We can even reject it with the custom validation error message for input component to show!

Can The Same Component Work With Both Sync And Async Handlers?

Yes! So the .then / .catch methods are only available on Promises but if you use async / await, you don't have to worry about whether the function is synchronous or returns a Promise.

await syncOnClickHandler(); // This doesn't throw error! It's safe to use await on anything

It's important to know that async functions are executed immediately, only the code after the first await goes to microtask queue. So if you plan to use event.preventDefault() or event.stopPropagation(), these calls should be made before using await.

async function onClick(e) {
    e.preventDefault(); // ✅
    await someApiCall();
    e.stopPropagation(); // this doesn't work because e.stopPropagation has to be called synchronously
}

Hope you found it helpful! Let's write more components with async friendly event handler :)