Building a Reusable Infinite Scroll Component With React

Sedang Trending 2 bulan yang lalu

How To Build A Reusable Infinite Scroll Component In React?

Lakindu Hewawasam

Bits and Pieces

Have you ever seen pages for illustration this?

This is nan landing page for nan Medium Publication — Bits and Pieces. Did you announcement nan measurement that nan published articles support loading arsenic I support scrolling down?

It eliminates nan request for nan personification to manually click connected a “Load More” fastener to load content, and keeps loading contented until location isn’t any.

This is simply a awesome personification acquisition betterment to immoderate app. It creates an illusion of an “infinite scroller” wherever nan personification does not person to execute immoderate further relationship to load much information onto nan site. For instance, cheque this out:

Most applications are presently built utilizing this “Load More” button. It loads an first group of information and enforces nan personification to manually load contented if they desire.

But, loading much information is ever desirable arsenic you’re scrolling down right? It gives nan earthy denotation that nan contented nan personification is searching for isn’t disposable and has to beryllium fetched.

So, that’s what I’m going to show you today. Let’s return a look astatine building our ain infinite scroller component. I’ll beryllium building this arsenic an independent constituent truthful that you tin freely usage this scroller successful your app pinch nary hassle of re-implementing it.

Pst, if you want to dive into nan code, checkout my Bit Scope.

To do so, I’m going to beryllium leveraging a next-generation build strategy called Bit. If you’re not acquainted pinch it, it’s a build strategy that lets you design, develop, build, trial and type constituent successful an independent environment.

This intends that I don’t person to support a elephantine monolith project, but alternatively activity connected each constituent independently and negociate these components done a tree:

Once Bit identifies a alteration successful a component, it leverages its CI Server — Ripple CI to build and propagate nan changes up nan character to make judge each components usage nan latest version.

So, let’s instal Bit earlier we build our scroller. To do so, usage Bit’s type head (BVMM) to instal Bit globally:

npx @teambit/bvm install

Next, to verify your installation, tally nan command:

bit --version

If you’ve installed Bit correctly, you’ll spot nan output:

Next, let’s bootstrap a React workspace to build our scroller on. This will rotation up nan dev environments basal to build pinch React.

To do so, tally nan command:

bit caller hello-world my-hello-world --env teambit.community/starters/hello-world --empty --default-scope dummyorg.elements

Tip: Replace dummyorg.elements pinch your Bit Username and Scope name.

Once you execute this command, you’ll spot nan output:

Next, caput complete to your task and motorboat nan dev server utilizing nan command:

bit start

Next, sojourn your dev server utilizing nan URL — http://localhost:3000 and you’ll spot nan output:

This workspace already comes preloaded pinch a bunch of components including an App constituent that lets america activity pinch a afloat functional React app disconnected nan box. So, let’s do immoderate cleanup and get free of nan inferior and nan UI components utilizing nan command:

bit region get-hello-world && spot region ui/hello-world

Afterward you should beryllium near pinch an situation and an app:

Next, let’s build nan infinite scroller. To do so, let’s create a React constituent utilizing nan command:

bit create respond ui/scroller --env my-react-env

You should spot nan output:

Next, unfastened your scroller.tsx record and see nan code:

import React, { useState, useEffect } from 'react';

export type ScrollerProps = {
/**
* civilization loader to use
*/
loader?: React.ReactNode;

/**
* nan contented wrong nan scroller
*/
children?: React.ReactNode

/**
* a usability that triggers nan load for data.
* @returns anything
*/
fetchMoreData: () => Promise<void>;
};

export usability Scroller({ loader, children, fetchMoreData }: ScrollerProps) {
const [isLoading, setIsLoading] = useState<boolean>(false);

useEffect(() => {
const handleScroll = () => {
// Set a period worth to trigger fetching data
const period = 100;

// Calculate nan region from nan bottommost of nan page
const scrollPosition = window.innerHeight + window.scrollY;
const bottomPosition = document.documentElement.offsetHeight - threshold;

// Check if nan personification has scrolled to nan bottommost aliases beyond nan threshold
if (scrollPosition >= bottomPosition && !isLoading) {
setIsLoading(true);
fetchMoreData().then(() => {
setIsLoading(false);
});
}
};

// Add arena listener for scroll event
window.addEventListener('scroll', handleScroll);

// Clean up: region arena listener erstwhile constituent unmounts
return () => window.removeEventListener('scroll', handleScroll);
}, [isLoading, fetchMoreData]);

return (
<div>
{children}
{isLoading && (loader || <p>Loading...</p>)}
</div>
);
}

As you tin see, we’ve implemented our scroller constituent to load much information if nan personification has scrolled beyond a defined period successful nan surface aliases if nan personification has scrolled to nan bottommost of nan screen. By doing so, we’re capable to execute an infinite scroller.

Additionally, we’ve besides introduced customizability into nan loader by letting users supply their civilization implementation of nan loader.

Next, let’s adhd immoderate compositions to this constituent to showcase it’s power. To do so, update nan scroller.composition.tsx pinch nan following:

import { useEffect, useState } from 'react';
import { Scroller } from './scroller';

export const BasicScroller = () => {
const [data, setData] = useState<string[]>([]);

useEffect(() => {
const loadData = async () => {
const newData = await fetchData();
setData(prevData => [...prevData, ...newData]);
}

loadData();
}, [])

const fetchMoreData = async () => {
// Simulating fetching much data
const newData = await fetchData();
setData(prevData => [...prevData, ...newData]);
};

const fetchData = (): Promise<string[]> => {
// Simulating API call
return caller Promise(resolve => {
setTimeout(() => {
const newData = Array.from({ length: 10 }, (_, i) => `Item ${i + 1}`);
resolve(newData);
}, 1000);
});
};

return (
<div>
<h1>Regular Scroller</h1>
<Scroller fetchMoreData={fetchMoreData}>
{data.map((item, index) => (
<div key={index} style={{ padding: '20px', border: '1px coagulated #ccc' }}>
{item}
</div>
))}
</Scroller>
</div>
);
}

export const ScrollerWithCustomLoader = () => {
const [data, setData] = useState<string[]>([]);

useEffect(() => {
const loadData = async () => {
const newData = await fetchData();
setData(prevData => [...prevData, ...newData]);
}

loadData();
}, [])

const fetchMoreData = async () => {
// Simulating fetching much data
const newData = await fetchData();
setData(prevData => [...prevData, ...newData]);
};

const fetchData = (): Promise<string[]> => {
// Simulating API call
return caller Promise(resolve => {
setTimeout(() => {
const newData = Array.from({ length: 10 }, (_, i) => `Item ${i + 1}`);
resolve(newData);
}, 1000);
});
};

return (
<div>
<h1>Custom Scroller</h1>
<Scroller fetchMoreData={fetchMoreData}
loader={<>Loading done civilization loader</>}
>
{data.map((item, index) => (
<div key={index} style={{ padding: '20px', border: '1px coagulated #ccc' }}>
{item}
</div>
))}
</Scroller>
</div>
);
}

Next, caput backmost to your Bit server and you should spot nan output:

If you inspect a creation successful greater detail, you tin spot it moving arsenic expected:

As you tin see, nan infinite scroll behaviour is moving arsenic expected, pinch nan civilization loader arsenic well.

So, let’s spell up and stock this for everyone to use.

To do so, tally nan command:

bit tag && spot export

Once you do so, you should spot a Ripple CI nexus generated connected your console. Click connected it to spot Ripple CI building your React component.

Ripple CI automatically understands nan changes made to nan constituent character and builds only nan changes to make judge that each components enactment successful sync.

Let’s leverage this scroller successful a React app. To do so, sojourn nan hello-world-app.app-root.tsx and update it pinch nan following:

import ReactDOM from 'react-dom/client';
import axios from 'axios';
import { useEffect, useState } from 'react';
import { Scroller } from '@dummyorg/elements.ui.scroller';

const getPosts = async (): Promise<string[]> => {
const resp = await axios.get('https://jsonplaceholder.typicode.com/posts');
return resp.data.map((post: any) => post.title arsenic string) arsenic string[];
};

export const HelloWorldApp = () => {
const [posts, setPosts] = useState<string[]>([]);

useEffect(() => {
getPosts().then((data) => {
setPosts(data);
})
}, [])

const loadMorePosts = async () => {
const newPosts = await getPosts();
setPosts((prev) => [...prev, ...newPosts]);
}

return (
<Scroller
fetchMoreData={loadMorePosts}
>
{posts.map((post) => <p>{post}</p>)}
</Scroller>
)
};

const guidelines = document!.getElementById('root');
ReactDOM.createRoot(root arsenic HTMLElement).render(<HelloWorldApp />);

We’ve updated nan app to leverage Axios and to usage nan JSON Placeholder API to dynamically load data.

So, lets trial this retired by launching nan app extracurricular of nan Bit server utilizing nan command:

bit tally hello-world-app

You should spot nan app loading and moving pinch nan scroller:

As you tin see, erstwhile nan personification keeps scrolling down nan window, nan API telephone is invoked automatically and information is fetched and rendered!

You tin tag and export your app pinch nan bid group we utilized earlier and you’ll spot Ripple CI build your App accordingly:

You tin leverage this constituent successful your React apps arsenic well! All you person to do is install it arsenic an NPM package:

And location we person it!

That wasn’t difficult was it? Now you’re capable to build awesome personification experiences without having to spell done nan hassle of manually implementing anything!

To cheque retired nan afloat implementation, sojourn my Bit Scope

I dream you recovered this article helpful.

Thank you for reading!