Reduce component loading time


Lazy loading is a concept that we can use to reduce the initial loading time of a particular page in web applications.
In the normal scenario when the user loads the page initially, all the contents of the page will be loaded, however, sometimes users don’t care what’s at the bottom of the page and don’t even bother to scroll. So uploading all the content would be in vain.
Using lazy loading we present The content is on user demand, so when the user scrolls down we load the content incrementally, not during the initial page view.
In this article, I will explain how we can load components in Next.js. But keep in mind that this is not for components that are rendered on the server side.
Consider a scenario where multiple components are loaded into a single component, such as a landing page with lots of sections and also with lots of API calls.
import Child1 from "../Child1";
import Child2 from "../Child2";
import Child3 from "../Child3";
import Child4 from "../Child4";
import Child5 from "../Child5";const ParentComponent = () => {
return <div>
<Child1/>
<Child2/>
<Child3/>
<Child4/>
<Child5/>
</div>}
Suppose that when users visit the above page, they only see a file Child1
And Child2
Content in the initial viewport.
To watch the contents Child3
The component and users below need to scroll down. However, some users may not even need to see the content at the bottom of the page.
But according to our code snippet once the user visits the page all 5 child components are shown and if there is any data fetching logic in these components there will be some API calls too.
As I mentioned earlier most of the time this is unnecessary as some users may not even want to see the rest of the content.
This is an example where lazy loading can be used to reduce the loading time of a component.
- As a first step, we need a way to detect the visibility of a particular component while the user is scrolling. Therefore, I will use
IntersectionObserver
.
Since this will be used more than once, I will create a custom hook.
import { useState, useEffect } from "react";const useOnScreen = (ref) => {
const [isIntersecting, setIntersecting] = useState(false); useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => setIntersecting(entry.isIntersecting)
); if (ref.current) {
observer.observe(ref.current);
} }, []) return isIntersecting;
}export default useOnScreen
This custom hook gets a reference and gets noticed. we use isIntersecting
State and state update using input.isIntersecting
. From the custom hook, we return a file isIntersecting
condition. if isIntersecting
The value is true, which means that the ref element is visible to the user.
2. In the next step we have to create references for each component of the child and observe the vision using our custom hook (useOnScreen
).
import Child1 from "../Child1";
import Child2 from "../Child2";
import Child3 from "../Child3";
import Child4 from "../Child4";
import Child5 from "../Child5";
import useOnScreen from "../useOnScreen";const ParentComponent = () => {
const child3Ref = useRef();
const child3RefValue = useOnScreen(child3Ref); return <div>
<Child1/>
<Child2/>
<div ref={child3Ref}>
{child3RefValue &&<Child3/>}
</div>
<Child4/>
<Child5/>
</div>}
right Now Child3
component only when Child3RefValue
is being correct. But there is another problem. Think of a scenario when the user scrolls down and then scrolls back. In such cases, the child3RefValue
It will update as false → true → false → true.
So when the value is updated to true twice, all Child3
The component will be rendered twice. We don’t need this to happen, so we need to prevent later rendering.
3. To prevent the component from being rendered more than once, we have to keep the state value in Parent
component:
import Child1 from "../Child1";
import Child2 from "../Child2";
import Child3 from "../Child3";
import Child4 from "../Child4";
import Child5 from "../Child5";
import useOnScreen from "../useOnScreen";const ParentComponent = () => {
const child3Ref = useRef();
const child3RefValue = useOnScreen(child3Ref);
const [isChild3Ref, setIsChild3Ref] = useState(false);useEffect(() => {
if (!isChild3Ref)
setIsChild3Ref(child3RefValue);
}, [child3RefValue])return <div>
<Child1/>
<Child2/>
<div ref={child3Ref}>
{child3RefValue && <Child3/>}
</div>
<Child4/>
<Child5/>
</div>}
now when child3RefValue
changes, and useEffect
Will run and if only isChild3Ref
is being false
The state will be updated. according to isChild3Ref
value, the Child3
The component will be rendered. So the component will only display once even though the user has scrolled up and down multiple times.
You can go even further with Next.js dynamic import. So Child3
component only when isChild3Ref
The state value is correct.
import Child1 from "../Child1";
import Child2 from "../Child2";
import Child4 from "../Child4";
import Child5 from "../Child5";
import useOnScreen from "../useOnScreen";
const Child3 = dynamic(() => import("../Child3"));const ParentComponent = () => {
const child3Ref = useRef();
const child3RefValue = useOnScreen(child3Ref);
const [isChild3Ref, setIsChild3Ref] = useState(false);useEffect(() => {
if (!isChild3Ref)
setIsChild3Ref(child3RefValue);
}, [child3RefValue])return <div>
<Child1/>
<Child2/>
<div ref={child3Ref}>
{isChild3Ref && <Child3/>}
</div>
<Child4/>
<Child5/>
</div>}
Lazy loading is a great way to prevent unnecessary content from being displayed on the page. With it, you can reduce the initial loading time of the page as child components will be rendered only on user request. Don’t forget to give it a try when you encounter similar situations.
If you are more interested in Next.js, you can refer to my article on Pre-rendering in Next.js.
Happy coding!