Understanding React.lazy() and Suspense
Recently, React has introduced ‘Suspense’ feature to support lazy loading. In this blog, we will see how to use it and a bit of back story.
During development, we have our code spread across multiple files. But when going for production, we merge all our files, including the libraries we have used, into a single javascript file using webpack. And that is the essense of single page application. While navigating between pages, the user need not have to wait for page loads (but may have to wait for data to load).
This behaviour is perfectly fine for small applications. But when our application grows in size, the single javascript file will become heavier. And moreover the user will not be using all the features. Actually what we are doing is, we are shipping code which is not being used.
So ideally, only the bare minimum code and the frequently used code should be shipped with the initial bundle and the rarely used heavy javascript should be loaded on demand. This improves the overall net performance of our application.
Lazy loading
Lazy loading is the practice of delaying loading the code till it is really needed. React based frameworks like Gatsby and Next.js inherently support lazy loading.
react-loadable is a famous library used to achieve lazy loading. But we dont need it with the newer version of React. We can use React.lazy() and Suspense combination.
The overall code will look something like the one below, and let me break it up with explanations further below.
import React, { Suspense } from "react";
const LazyComponent = React.lazy(() => import("./LazyComponent"));
class App extends React.Component {
state = {
showLazyComponent: false
};
...
render() {
return (
<main>
...
{
this.state.showLazyComponent && (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
)
</main>
);
}
}
export default App;
We have a ‘LazyComponent’ which we want to load on demand. We use React.lazy to import the dependency as below.
Note: For convienece sake I named it as LazyComponent, but in real time we can give a meaningful name.
const LazyComponent = React.lazy(() => import("./LazyComponent"));r
The import happens within an arrow function, which will be called on demand.
While using the LazyComponent in the JSX, we need to ensure that it is wrapped within <Suspense> tag.
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
Suspense need not always have to be the immediate parent of the LazyComponent. It can be present anywhere in the ancestor heirarchy.
The ‘fallback’ props of ‘Suspense’ component is easily predictable. It is the placeholder component till the real component is loaded. Apart from the inline JSX, it can accept valid react component.
And remember, this placeholder will occupy the entire children region of ‘Suspense’.
<Suspense fallback={<div>Loading...</div>}>
<h1>Some static Text</h1>
<LazyComponent />
</Suspense>
For example, in the above snippet, the <h1> tag will not be visible when the loading is in progress.
The Suspense block can have more then one lazy component as children.
<Suspense fallback={<div>Loading...</div>}>
<h1>Some static Text</h1>
<LazyComponent />
<LazyComponent2 />
</Suspense>
In this case, the children will be displayed, only after all the lazy components are loaded.