ref – https://beta.reactjs.org/reference/react/lazy#suspense-for-code-splitting
Lazy-loading components with Suspense
Usually, you import components with the static import declaration:
1 |
import MarkdownPreview from './MarkdownPreview.js'; |
To defer loading this component’s code until it’s rendered for the first time, replace this import with:
1 2 |
import { lazy } from 'react'; const MarkdownPreview = lazy(() => import('./MarkdownPreview.js')); |
Now that your component’s code loads on demand, you also need to specify what should be displayed while it is loading. You can do this by wrapping the lazy component or any of its parents into a
1 2 3 4 |
<Suspense fallback={<Loading />}> <h2>Preview</h2> <MarkdownPreview /> </Suspense> |
the code for MarkdownPreview won’t be loaded until you attempt to render it. If MarkdownPreview hasn’t loaded yet, Loading will be shown in its place.
1 2 3 4 5 6 |
{showPreview && ( <Suspense fallback={<Loading />}> <h2>Preview</h2> <MarkdownPreview markdown={markdown} /> </Suspense> )} |
First let’s look at a function delayForDemo that will delay the the lazy loading of our MarkdownPreview.
The import() returns a Promise that will be fulfilled once the module is loaded completely.
Hence, our parameter of promise receives imported components.
We do a timeout of 2 seconds, and then return the promise right after.
1 2 3 4 5 6 |
// Add a fixed delay so you can see the loading state function delayForDemo(promise) { return new Promise(resolve => { setTimeout(resolve, 2000); }).then(() => promise); } |
We then use it on the import like so:
1 |
const MarkdownPreview = lazy(() => delayForDemo(import('./MarkdownPreview.js'))); |
The whole point of this is to show that while an import component is being lazy loaded, we must show the fallback Loading component.
1 2 3 4 |
<Suspense fallback={<Loading />}> <h2>Preview</h2> <MarkdownPreview markdown={markdown} /> </Suspense> |
Notice
1 2 3 4 |
const [showPreview, setShowPreview] = useState(false); ... ... <input type="checkbox" checked={showPreview} onChange={e => setShowPreview(e.target.checked)} /> |
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 29 30 31 32 33 |
import { useState, Suspense, lazy } from 'react'; import Loading from './Loading.js'; const MarkdownPreview = lazy(() => delayForDemo(import('./MarkdownPreview.js'))); export default function MarkdownEditor() { const [showPreview, setShowPreview] = useState(false); const [markdown, setMarkdown] = useState('Hello, **world**!'); return ( <> <textarea value={markdown} onChange={e => setMarkdown(e.target.value)} /> <label> <input type="checkbox" checked={showPreview} onChange={e => setShowPreview(e.target.checked)} /> Show preview </label> <hr /> {showPreview && ( <Suspense fallback={<Loading />}> <h2>Preview</h2> <MarkdownPreview markdown={markdown} /> </Suspense> )} </> ); } // Add a fixed delay so you can see the loading state function delayForDemo(promise) { return new Promise(resolve => { setTimeout(resolve, 2000); }).then(() => promise); } |