Loading components asynchronously in React app with an HOC
Tags: react, hoc, components
Published: 2018-01-24 09:46:05

---
title: Loading components asynchronously in React app with an HOC
published: true
description: It’s considered a good practice to load big components upon request. Here is a way of doing that using HOC.
tags: react,hoc,components
---


![](https://thepracticaldev.s3.amazonaws.com/i/mrmodbtgw57x3ar8t2nq.jpg)

In the era of single-page applications, you can write (almost) any web app with your favorite **React**. Some apps, in fact, can be really huge! Imagine you are developing a Facebook clone… Pretty big, huh?

Now, as you might know, when your Webpack configuration does its magic on your code, it generates a single **bundle.js** file, that contains all the code needed on the front end. It includes all your components in addition to a lot of additional building blocks. So, the bigger the app, the larger the file. And, of course, big files take longer to download. Thus, the first page load slows down. And, in fact, the user might never visit a lot of the loaded pages and never see a lot of components.

It’s considered a good practice to break down the initial **bundle.js** file into chunks and load components upon request. Thus, the pages the user does not have the intention to visit and the components that will never be rendered will never be loaded.

There are a lot of different approaches to do this. I’ll share the one that involves **HOCs** :)

#What is an HOC?

> *A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.*

Think of an HOC as a wrapper around your components, that applies some common state and behavior alternations to them when they are created. An HOC is basically a function, that takes a component, and returns another component. You can use them as normal components in your *jsx*. [Here’s the detailed documentation of Higher-order Components](https://reactjs.org/docs/higher-order-components.html).

![](https://thepracticaldev.s3.amazonaws.com/i/a7a0ctfk3rc40uydpfcy.jpg)

So what we’re going to do, is that we’ll define an HOC and apply it to those components that we want to be loaded asynchronously.


#The Async Component HOC

Let’s create a file that will contain our HOC. We’ll call it **asyncComponent.js**. I like to have a separate folder named “hoc” in my project for holding all the higher-order components.

Here are the file contents:

```javascript
//hoc/asyncComponent.js

import React, {Component} from 'react';

const asyncComponent = (importComponent) => {
    return class extends Component {
        state = {
            component: null
        }

        componentDidMount() {
            importComponent()
                .then(cmp => {
                    this.setState({component: cmp.default});
                });
        }

        render() {
            const C = this.state.component;
            return C ? <C {...this.props}/> : null;
        }
    }
};

export default asyncComponent;
```


As you can see, it simply returns a function that receives another function and returns an *anonymous class* extended from the **React Component**. So, basically, our *asyncComponent* is a function that returns a *component*.

Now, **importComponent** is a function, that simply returns a component import. It might look something like this:


```javascript
const impFn = () => {
    return import('./components/Card');
}
```

Every time **importComponent** is called, React will try to import the component. It will download a **chunk.js** file containing the imported component.

#Using asyncComponent

Let’s see how we can use this component and what what will happen if we do so. We’ll try to use it in another functional component as an example.


```javascript
//components/Container.js

import React from 'react';
import asyncComponent from '../../hoc/asyncComponent';

const AsyncButton = asyncComponent(() => {
    return import('../Button');
});


const container = () => {
    return (
        <div>
            <h1>Here goes an async loaded button component</h1>
            <AsyncButton/>
        </div>
    );
};

export default container;
```

Here, instead of using the < Button /> component in our DOM, we define a new component called **AsyncButton**. Knowing how we have defined the **asyncComponent**, we can guess that **AsyncButton** will be assigned a new type of Component. But what happens when it is added to the DOM? The answer is in the **asyncComponent**.

Apparently, when the **AsyncButton** is mounted (see *componentDidMount*), it calls our **importComponent** function. In our case, it will import and return the **Button** component. Until the import is done, the rendered DOM will be empty. When the missing component is loaded via a chunk file download, it will be added to the **AsyncButton** component’s state and the latter will re-render. Now, our async component will simply render the downloaded **Button** component with passed props.

And that’s it. We have made our **Button** component be fetched only if it is actually mounted ;)

#Routing with Async Components

When you have a lot of container components (aka pages) in your app, it would be reasonable to initially load only the pages that are most likely to be visited and fetch the rest asynchronously. Our **asyncComponent** is just perfect for that. You’ll need to use it exactly like we did with the Button before.

Here’s a simple example to play with. Assume we have all our routing in a separate file with only 2 routes defined for simplicity. The home page that is initially loaded, and the user profile page that is not guaranteed to be visited.


```javascript
//Routes.js

import React, {Component} from 'react';
import {Route, Switch} from 'react-router-dom';

import HomePage from './containers/HomePage';

const AsyncProfilePage    = asyncComponent(() => {
    return import('./containers/ProfilePage');
});

class Routes extends Component {
    render() {
        return (
            <Switch>
                <Route exact path='/' component={HomePage}/>
                <Route exact path='/profile' component={AsyncProfilePage}/>
            </Switch>
        );
    }
}

export default Routes;
```

Thus, the code for user profile page will be downloaded only if the user clicks on a link in home page that displays the desired page.

Hope you learned something new here, and happy Reactive coding! 🤘