You may have seen this or something similar many times. But lets look briefly at what exactly lazy is doing, and how we can use that to do something else.

In the code above, lazy takes a callback containing a dynamic import — and then renders the default component returned from it. Coupled with suspense, we can wait for the component to be loaded before rendering it. Lazy currently however lets you render default components, as it just wraps the imported module.

If you have used dynamic import before, you will know that it returns a Promise that resolves with the es6 module inside it. Remember, promises can be chained — and lazy is expecting to receive an es6 module after the promise chain has completed. This means that we can do more than just initialise our module here. To illustrate this, let us add in a simple timeout:

const MyLazyComponent = lazy(() => new Promise(async resolve => {

const module = await import("./MyLazyComponent"); setTimeout(() => resolve(module), 1000);

}));

If you were to run this, MyLazyComponent will load the module, then waita further second before completing. Suspense will therefore show the loading message during all of this time. We have made lazy to wait for something more than just loading in the module.

Well, this is very well and good but completely useless. However, we are merely using this example to demonstrate the underlying point — we can run any asynchronous code here, as long as at the end we resolve with the module.

For instance, say your route needs to fetch some data from an API prior to it running. Normally we could put this into a useEffect after it renders, or perhaps wrap it in a higher order component, or whatever else — here, we can leverage the ability of lazy and actually complete the call before we return the module.

Assume that we had our lazy component as so:

export default data => () => <MyComponent data={data} /> const MyLazyComponent = lazy(() => new Promise(async resolve => {

const module = await import("./MyLazyComponent");

const response = await fetch("/api/data");

const jsonResponse = response.json();

resolve({

...module,

default: module.default(jsonResponse)

});

}));

We could make the call, and populate our component with data from the API prior to completing the lazy loading of the component. So when lazy returns, it will render the component with the data from the API already present.

Of course this example is very minimal and not that useful — however it opens up possibilities of what can be done, and how lazy — may not be as lazy as it seems!