Lazy Loaded React Components With Webpack 2
Tags: react, optimization, bundling
Published: 2017-02-06 00:12:47

---
title: Lazy Loaded React Components With Webpack 2
published: true
description: Making components load on-demand with Webpack 2.
cover_image: 
tags: react, optimization, bundling
---

_TL;DR Here is a [repository](https://github.com/kay-is/webpack-react-hoc) with a working example. :)_

In my posts of the last weeks I told you about two things. [How to improve your React code-base with higher order components (HOC)](https://dev.to/kayis/higher-order-with-context) and [how to make parts of your single page application load on-demand with Webpack 2](https://dev.to/kayis/dynamic-imports-with-webpack-2).

In this post I will show you how to merge these into one.

Why?

Because it's cool!

And it lets you save even more bandwidth. 

You could create modals, pop-ups, context-menus, notifications, dialogs and what-not and the needed code gets loaded when the feature is needed.

I'm not telling this is the silver bullet, you should check with your users which stuff isn't needed too often or too heavy weight, and only move these into other chunks, otherwise your users will end up with loading indicators for every click they do.

Anyway, lets get started!

I will refer to code in an example [repository](https://github.com/kay-is/webpack-react-hoc) I made.

First I created a `<BigList>` component, which is basically an unsorted list with about 1000 list items, this will simulate a bit of loading time.

Second I created a HOC called `lazify`, which is used to create a wrapper for our `<BigList>`.

Lazify differs from regular HOCs, because it can't get a reference to the constructor of the component it wraps. Because, well, it's not loaded right now.

We also can't give it simply the path to the file with the definition of our target component.

Why not?

Because Webpack searches the code for `System.import(...)` and creates new chunks depending on the path argument. If it finds something like `System.import(variable)` it can't make any educated guesses about "which" files it should move to another chunk.

Okay, so we have to give lazify `System.import('/path/to/our/Component')`?

No, because this would be executed when the `lazify` function is called and `lazify` would get the promise, that resolves to the module.

So what do we need to pass to `lazify` to get things running, but only if the lazified version of our component is rendered?

Well, the best thing you could use in any place, _a function_.

A function that will call `System.import` when it's needed.

So instead of creating the lazy loaded version like this:

    import BigList from 'BigList'
    import lazify 'lazify'

    export default lazify(BigList)

which would load everything statically and not provide us any benefit.

We the file needs to look like this:

    import lazify from 'lazify'

    export default lazify(() => System.import('BigList'))

Now `lazify` is able to create our wrapping component (WC) and give it access to the function that will load the right import.

    import React from 'react'

    export default
    function lazify(load) {

      return class LazyComponent extends React.Component {

        constructor() {
          super()
          this.state = {Component: null}
        }

        componentDidMount() {

          load().then(m => this.setState({Component: m['default']}))

        }

        render() {

          const {props} = this
          const {Component} = this.state

          return Component? <Component {...props}/> : <span>Loading...</span>

        }

      }

    }

The new component will have a `Component` state, initialized to `null`.

The first time it's mounted, it will render a loading indication, then `componentDidMount` will be called by React and our WC will call the `load` function we passed to `lazify` earlier.

This function calls `System.import` and will return its promise. The promise will resolve to our loaded module and this should export a React component as default.

When default export, the _real component_ (RC) we really want to render is stored in the state of the WC, the WC will render again, this time with the RC and pass its `props` down to it, so the parent of WC won't be the wiser about what happened.

My idea about the directory structure here was to store the RC into its own folder in an `index.js` and the WC in `lazy.js`.

So when you use it you are aware that it's a lazy version.

    import BigList from 'BigList'
    import LazyList from 'BigList/lazy'