Skip to main content

Infinite Scroll

Do you have a list of data that users scroll through? Maybe it's a list of payments, or transactions or bills. Probably something where you've scrolling further back in time. Well, we have a component that integrates with react-query's infinite query to load in more elements from the list as the user scrolls down the page.

Check out this example:

In InfiniteBillsList.tsx, we import the utility InfiniteScroll. We pass this component the props from the useInfiniteQuery hook (fetchNextPage, hasNextPage, data ... etc), as well a the RenderComponent={BillsList}, which is given below.

InfiniteBillsList.tsx
import {
InfiniteScroll,
} from '@krakentech/blueprint-utils';

// standard list component that takes data and displays list with items
import BillsList from './BillsList'

// example custom utility that we want to pass to our BillsList component
import { createDownloadUrl } from './utils';

const InfiniteBillsList = ({
fetchNextPage,
hasNextPage,
data,
error,
isLoading,
}) => {
return <InfiniteScroll
loadMoreText={'Load more'}
loadFn={fetchNextPage}
hasNextPage={hasNextPage || false}
data={data}
error={error}
isLoading={isLoading}
downloadBillUrlFunc={({ billId }: { billId: string }) =>
createDownloadUrl(billId)
}
RenderComponent={BillsList}
/>;
};


In BillsList.tsx we define the standard React component we want to render the items in the list. This is the component that was passed to the RenderComponent prop of InfiniteScoll. The RenderComponent is passed the data and error props, along with any custom props we defined like downloadBillUrlFunc.

BillsList.tsx
import { useMemo } from 'react';
import { Loader, Typography, Error, Stack, Container } from '@krakentech/coral';
import { BillListItem } from './Bills';


const BillsList = ({
data,
error,
downloadBillUrlFunc,
}) => {
const statements = useMemo(() => data?.pages?.flat(1), [data]);

if (statements) {
return (
<Container marginBottom="lg">
<Stack gap="sm" direction="vertical">
{statements?.length ? (
statements.map((statement) => (
<BillListItem
key={statement.id}
page={statement}
downloadBillUrl={downloadBillUrlFunc({
billId: statement.id,
})}
testId={`bill-${statement.id}`}
/>
))
) : (
<Typography variant="h3">
No bills to display
</Typography>
)}
</Stack>
</Container>
);
}

if (error) {
return <Error />;
}

return <Loader />;
};

And here is an example of this component in action. If you scroll to the bottom, a 'Load more' button is briefly visible. This button is provided to allow for keyboard accessibility. If you open the developer tools for the page, you'll also see the mocked request trigger in the network tab.