Martin Nuc
Software engineer at Productboard
10.8 MB
โ๏ธ
split app into chunks by routes
const loadMyComponent = () =>
import(
/* webpackChunkName: "awesome-chunk" */
'src/js/MyComponent'
);
const LazyMyComponent = React.lazy(loadMyComponent);
<Suspense fallback={<LoadingSpinner />}>
<LazyMyComponent />
</Suspense>
10.8 MB down to 3.8 MB
๐
๐ really fast parts
๐ reasonably fast
๐ข slow large pages
300ms
1500ms
Spinner
Skeleton
No indicator
the fallback is always rendered
๐จ
=
spinner shows even when not necessary
const Suspense = ({children, fallback}) => {
try {
return children;
} catch {
return fallback;
}
}
const Suspense = ({children, fallback}) => {
try {
return children;
} catch(thrownPromise) {
thrownPromise.then(() => rerender());
return fallback;
}
}
const Suspense = ({children, fallback}) => {
try {
return children;
} catch(thrownPromise) {
thrownPromise.then(() => rerender());
return fallback;
}
}
First render always throws
๐ก postpone rendering of fallback
<Suspense fallback={
<DelayedComponent delay={300}>
<LoadingSpinner />
</DelayedComponent>
}>
<ComponentFetchingData />
</Suspense>
export const DelayedComponent = ({children, delay}) => {
const [shouldDisplay, setShouldDisplay] = useState(false);
useEffect(() => {
const timeoutReference = setTimeout(() => {
setShouldDisplay(true);
}, delay);
return () => {
clearTimeout(timeoutReference);
};
}, [delay]);
if (shouldDisplay) {
return children;
} else {
return null;
}
}
โ fallback renders only when needed
Identify slow pages
โ ๏ธ
๐ we had no visibility into components rendering
๐ก track DelayedComponent lifecycle
DelayedComponent
nothing
Spinner
Suspended content
loading done
300ms
โฑ rendered
โฑ fallback displayed
โฑ component unmounted
โ identified slow pages (>1500ms)
๐ง crafted skeletons for them
๐
Spinner
300ms
350ms
โ Fast spinner here!
Finished loading
Spinner
300ms
350ms
Finished loading
600ms
250ms
no fast spinner or faster render?