In this article, we are going to optimize our listing component, which displays data. Once we are through it you will learn how to improve the performance of your application and make the experience of your application better. Without further ado, let us get started! 🤓
Why Lazy Load Your Data? 🙋🏽
Imagine your application has a screen that has three listing components being rendered, and every list can have thousands and thousands of records being fetched from your server with REST. Now you could get all of your data at once but that means your communication with the server could take time since it has to bring a bulk of data, which wastes the users’ time along with the performance of your application. How can this be solved?
- Give pagination to your user so that they can access the page of their own choice
- Trigger the next batch of data once the user reaches the end of the list
Now both these solutions are valid because they serve different purposes and are used according to the requirement but in this one, we are going to work with automatically fetching the next batch of data once the user reaches the end of the list.
Infinite Scroll React
We are going to use a package to give us the support of an infinite scrollable list, feel free to make one of your own if you like
npm i react-infinite-scroll-component
We are following the codebase of one of our tutorials on react query. Following the layered architecture in that one, we are going to make some changes in our API layer
const fetchPlanets = async ({ pageParam = 1 }) => { return axiosInstance({ url: `planets/?page=${pageParam}`, method: "GET", }).then(({ data }) => { const response = { results: data?.results, next: data.next === null ? undefined : pageParam + 1, }; return response; });};
We have added pageParams with a default value of 1, our server raw response looks something like this
{
"count": 60,
"next": "https://swapi.dev/api/planets/?page=2",
"previous": null,
"results": [
{
"name": "Tatooine",
"rotation_period": "23",
"orbital_period": "304",
"diameter": "10465",
"climate": "arid",
"gravity": "1 standard",
"terrain": "desert",
"surface_water": "1",
"population": "200000",
...
},
]
}
Coming onto our custom hooks, we are going to replace useQuery with useInfiniteQuery by react query, which is going to help us with the lazy loading and again with minimal code 😎
const usePlanets = () => {
return useInfiniteQuery(["get-planets"], fetchPlanets, {
getNextPageParam: (lastPage) => lastPage.next,
select: (data) => data,
});
};
We have used getNextPageParam option in this one so that we could check what’s coming on the next page using react query, now that we are done with our custom hook let’s move on to the actual component
const CustomComponent = () => {
const { data: planets, isLoading, hasNextPage } =
usePlanets();
const [dataLength, setDataLength] = useState(0);
useEffect(() => {
if (!!planets && !!planets?.pages && planets?.results) {
setDataLength(
planets.pages.reduce((counter, page) => {
return counter + page.results.length;
}, 0)
);
}
}, [planets]);
return (
<InfiniteScroll
dataLength={dataLength}
next={fetchNextPage}
hasMore={!!hasNextPage}
loader={<div>Automatically fetching next page...</div>}
>
{planets?.pages?.map((pageResult, i) => {
return (
<React.Fragment key={i}>
{pageResult.results.map((planet) => (
<Planet
key={planet.id}
planet={planet}
/>
))}
</React.Fragment>
);
})}
</InfiniteScroll>
)
}
export default CustomComponent
Here we have used InfiniteScroll component which we previously installed to lazy load our list, then we started mapping our data as children of the component and providing next, hasMore, and loader from react query as well.
MOMENT OF TRUTH 🤓
Wrap Up
Well, this one was long with a lot of code 😮💨 but we did, get yourself a cookie you did a great job. We learned how to make the experience of our application seamless with react query lazy loading. While our list of planets is lazily fetched with the help of infinite scroll. I’ll see you at the next one. Till then, Take care.
💬 Leave a comment