3 min read
At my company, I was tasked to improve the UX of our web application by making use of infinite loading.
As our web app uses ant design to provide our users with an amazing and stunning UI, I had to look for a solution that is supported by ant design out of the box.
Unfortunately, there wasn’t anything like a prop that I could pass to the List component to get the infinite scroll working.
However, ant design uses react-infinite-scroll-component, a third-party library to demo the infinite scroll effect on their Scroll loaded example.
Despite the fact that ant design uses a third-party library to showcase the use of infinite scroll, it didn’t meet the requirements because the library kept on executing the load more function even when the last item is not visible on the viewport(screen). It caused a jumpy effect that was a failure in terms of improving the UX of the application.
Enough said 😋! Let’s dive into how we managed to provide a seamless infinite scroll behavior with the help of IntersectionObserver API to our web application.
Let’s start by putting in place the logic that we shall use to check if the last item is visible on the viewport.
const observer = useRef<IntersectionObserver>();
const lastItemRef = useCallback(async (node: HTMLDivElement) => {
if (loading) return;
if (observer.current && items.length) {
observer.current.disconnect();
return;
}
observer.current = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && items.length) {
onLoadMore();
// Don't forget to disconnect the observer after your callback function
observer.current.disconnect();
}
});
if (node) observer.current.observe(node);
},
[loading, items],);
Hold on 🖐! Let’s explain what’s going on here.
With that explanation out of the way, let’s move to the next step 😊.
export const InfiniteList = forwardRef<HTMLDivElement, IInfiniteList>(({
loading,
grid,
items,
renderItem,
onLoadMore,
}: IInfiniteList,
ref,
) => {
return (
<List
loading={loading}
loader={<div>Load more</div>}
grid={grid}
dataSource={items}
renderItem={(item, index) => {
if (index === items.length - 1) {
return (
<>
{renderItem(item)}
<div ref={ref} />
</>
);
}
return renderItem(item);
}}
/>
);},);
Well! There are not enough magical kinds of stuff going here but let’s try to give some explanations.
<InfiniteList
items={items}
loading={loading}
grid={grid}
renderItem={renderItem}
onLoadMore={onLoadMore}
ref={lastItemRef}
/>
And that’s pretty much it🤩 !