October 29, 2018
reactReact 16.6.0 introduced React.lazy
, which allows you to code-split using the new Suspense API.
Siddharth Kshetrapal came out with a great video showing how this works in 60 seconds. I’d recommend watching it –– it’s really well-done.
I’ve built a Github clone based off of Siddharth’s example. Hopefully this will help people who prefer reading to watching videos, or who to be walked through it step by step!
React.lazy allows developers to block UI from rendering until a pre-determined condition is met. For example, maybe you don’t want your component to render until you get a response back from an endpoint.
Before React.lazy, you had to load all of the files that were ever going to be visible in that view, even if some of them were hidden.
For example, imagine you built an e-commerce site like I’m working on at Harry’s:
In the upper-right hand corner, we have a cart icon. When you click it, a PanelOverlay
component slides out from the right-hand side.
Right now, we load the PanelOverlay
component when we load /
. But with React.lazy
, we could dynamically import that component so that it’s only being loaded after it has been clicked! That should allow us to load the homepage even more quickly.
You might be wondering how lazy() is different from react-loadable, for example. Sean T. Larkin explains it well in this tweet:
Well lazy() let's you not need a separate library to have easy code splitting. It's now out of the box through React.lazy. what loadable-component and react-universal-component do in addition handle some SSR stuff. They should also just use the lazy() API instead internally.
— Sean Thomas Larkin (肖恩) (@TheLarkInn) October 25, 2018
lazy()
lets you code-split without adding another dependency to your codebase. It makes a best practice (code-splitting) easier, which will encourage developer to use it, and will make writing performant React apps more seamless.
I built a demo of code-splitting with React.lazy
using Github’s API to show you exactly how to implement it in your own application.
Below is a .gif of how code-splitting would look on a low-end mobile device. I slowed down so it’s easy to see every distinct step of the process.
Let’s walk through what’s happening here:
Let’s also take a look at the network tab so you can see the code-splitting in action.
When we don’t code-split, two chunks are loaded immediately.
On the other hand, when we implement code-splitting, we load two chunks initially, and then a third once we actually search for a Github username.
The best part about this React feature is how easy it is to implement.
Let’s start with a simple implementation example. @ggrgur provided an awesome example on twitter:
🔥🔥Asynchronously | Dynamically | Lazy 🔥🔥 loading component with #React Suspense and @webpack with proper code splitting
— Grgur Grisogono (@ggrgur) October 25, 2018
This is *the* reason to upgrade to ⭐️@reactjs 16.6⭐️ pic.twitter.com/qN3WkmoTPL
There are three important pieces to code-splitting in React:
import React, { Suspense, lazy } from "React";
const Deferred = lazy(() => import("./Deferred"));
<Suspense fallback={<div>Fallback Component</div>}>
<Deferred {...props} />
</Suspense>
And now I’ll share an entire example:
// Import Suspense and lazy from React
import React, { Component, Suspense, lazy } from "react";
import axios from "axios";
import styled from "styled-components";
import { Container, Row, Col } from "react-grid-system";
import { SearchBar } from "./components/SearchBar";
import { SearchInput } from "./components/SearchInput";
// Dynamically import the file
// you don't want to load until later
const Repos = lazy(() => import("./Repos"));
class App extends Component {
// Some lifecycle and class methods here
render() {
const { value } = this.state;
return (
<Container>
<div className="App">
// Search Bar Code
{this.state.loading ? (
<Row>// Fetching data message</Row>
) : (
<Row>
<Col sm={12} md={2}>
{this.state.profile ? (
<h1>{this.state.profile.login}</h1>
) : null}
</Col>
<Col sm={12} md={10}>
// Here is where we actually use React.lazy // We check to make
sure the data came back from the API // Then we wrap the
component that's being dynamically // imported in `<Suspense />`
and provide a fallback // component
{this.state.repos.length > 0 ? (
<Suspense fallback={<Blurred />}>
<Repos repos={this.state.repos} />
</Suspense>
) : null}
</Col>
</Row>
)}
</div>
</Container>
);
}
}
export default App;
If you like what you're reading, I send out a newsletter whenever I publish a new post. You can always unsubscribe.