React Dynamic Import / Import Component on Demand Mar 3rd 2020 Words: 410

Giant chunk of JS may slow down the site’s first render significantly. So instead of packing every module imported to one huge JS, it is better to strip off those rarely accessed modules and make them load only when required.

react-loadable is the handy tool for this job.

Original code without dynamic import

Assume we are writing a React component that renders a rarely accessed page in certain state.

1
2
3
4
5
6
7
8
9
10
import BigFatPage from "./BigFatPage.js";

class MyComponent extends React.PureComponent {
render (
//...
return (this.state.showPage &&
<BigFatPage/>
);
);
}

Basic usage

1
2
3
4
5
6
7
8
9
10
11
12
13
import Loadable from "react-loadable";

class MyComponent extends React.PureComponent {
render (
//...
if (this.state.showPage) {
const BigFatPage = Loadable({
loader: () => import("./BigFatPage.js")
})
return (<BigFatPage/>);
}
);
}

Do not use variable path in import argument if using Webpack, because it can not be resolved.

In the Network monitor under DevTools, now the BigFatPage.js will load only when MyComponent showPage state is true.

With a loading message or error message

Of course we cannot show a blank page while the component is loading. react-loader also allows us to show a loading message and timeout as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import Loadable from "react-loadable";

class MyComponent extends React.PureComponent {
render (
//...
if (this.state.showPage) {
const CustomLoading = (props) => {
if (props.error) {
console.error(props.error);
return (<div>Some error occurred</div>);
} else if (props.timedOut) {
return (<div>Component still loading, but you'd better retry</div>);
} else if (props.pastDelay) {
return (<div>Page loading... Sit back and relax</div>);
} else {
return null;
}
};
const BigFatPage = Loadable({
loader: () => import("./BigFatPage.js"),
loading: CustomLoading,
delay: 300, // Only show loading message after 0.3s to avoid flash the page
timeout: 10000 // Trigger timeout after 10s
})
return (<BigFatPage/>);
}
);
}

if (props.timedOut) brach in CustomLoading must be placed before if (props.pastDelay)

Custom Rendering

If some props has to be passed to the dynamic imported module, render should be overwritten.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//...
const props = this.props; // To access inside render function

const BigFatPage = Loadable({
loader: () => import("./BigFatPage.js"),
loading: CustomLoading,
render(loaded) {
const BigFatPageComp = loaded.default;
return <BigFatPageComp passed={props.arg}/>
},
delay: 300,
timeout: 10000
})
return (<BigFatPage/>);

EOF