In this article we are going to discuss how we can improve the performance of our apps by loading only the JavaScript that the user needs at any point in time, reducing the amount of code they have to download and execute on page load, and making the app interactive faster.😎 Cool Isn't it?
We’ll use React.lazy and Suspense to delay the loading of a complex component like KendoReact’s StockChart until a button is clicked.
Understanding Dynamic Imports
Instead of sending a big bundle with all the code for our app on initial page load, we can send smaller bundles gradually as the user interacts with the app. To do this we’ll rely on a modern JavaScript feature called dynamic imports. A dynamic import returns a promise that will resolve once the required module gets transferred over the network, and is parsed and executed by the JavaScript engine.
A static import looks like this:
import { concat } from "./utils";
console.log(concat("A", "B", "C"));
While a dynamic import looks like this:
import("./utils").then(utils => {
console.log(utils.concat("A", "B", "C"));
});
Tools like Create React App and webpack understand what we’re trying to do with these dynamic imports, and will output separate JavaScript files for these lazy-loaded bundles. If we’re configuring webpack ourselves, it may be a good idea to spend some time reading webpack’s documentation on code-splitting
Lazy-Loading with React.lazy and Suspense
Starting with version 16.6, React includes a built-in React.lazy function that makes it very easy to split an application into lazy-loaded components using dynamic imports.
You can turn this:
import StockChartContainer from "./StockChartContainer";
Into this:
const StockChartContainer = lazy(() => import("./StockChartContainer"));
And React will automatically load the bundle containing our StockChartContainer component when we try to render it for the first time.
We’ll want to wrap this lazy component inside a Suspense component, which will allow us to show some fallback content while things are being loaded. Let’s see what that looks like.
Example
In this example we are going to be loading a complex component containing KendoReact’s StockChart, but only after the user clicks on a button. This way we’ll avoid sending the user more code than they need on initial load.
We’ll store state to track whether our complex component needs to be displayed:
class App extends Component {
constructor(props) {
super(props);
this.state = {
showChart: false
};
}
}
Then, we’ll implement a handleClick function that will toggle state when the user clicks a button:
class App extends Component {
// ...
handleClick = () => {
this.setState(prevState => ({
showChart: !prevState.showChart
}));
};
}
Now we just need to put it all together in the render method:
const StockChartContainer = lazy(() => import("./StockChartContainer"));
class App extends Component {
// ...
render() {
const { showChart } = this.state;
const buttonText = showChart ? "Hide Stock Chart" : "Show Stock Chart";
const chartComponent = showChart ? <StockChartContainer /> : null;
const loadingComponent = <div>Loading...</div>;
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Stock Chart</h1>
<div className="App-button">
<Button primary={true} onClick={this.handleClick}>
{buttonText}
</Button>
</div>
</header>
<div className="App-chart">
<Suspense fallback={loadingComponent}>{chartComponent}</Suspense>
</div>
</div>
);
}
}
Conclusion
If we send too much JavaScript to our users, we’ll make the browser’s main thread busy, and it won’t be able to respond to user interaction. Lazy-loading components of our app that are not needed on initial page load will help reduce the amount of work the browser has to do, which will drive down our time-to-interactive, and provide a better experience to our users, especially those on mobile devices. React.lazy and Suspense make it so easy to do that we really have no excuse!😎
Top comments (3)
Hey, thanks for sharing! BTW, you can tag code blocks with a language to get syntax highlighting by adding the language extension (e.g.
js
,c
,cpp
,java
) after the the first three backticks.Thanks, well noted!
We shouldn’t be seeing class components in react guides in 2020, besides that thank you.