@spa-tools/interaction-hooks
useInfiniteScroll()
Stop time-warping your users back to the 1990's with antiquated pagination controls. Instead, streamline your data pagination experience by implementing infinite scrolling with the useInfiniteScroll
hook.
Usage
import { useEffect, useRef } from 'react';
import { useCallEndpoint } from '@spa-tools/api-client';
import { useInfiniteScroll } from '@spa-tools/interaction-hooks';
// here we create a custom hook to fetch recipes from a server
// using the useCallEndpoint hook from the @spa-tools/api-client package
function useGetRecipes() {
return useCallEndpoint(
'https://dummyjson.com/recipes',
{
requestOptions: { recordLimit: 10 },
serverModelOptions: { jsonDataDotPath: 'recipes' },
},
// we pass true to enable appending of new records
true
);
}
function UseInfiniteScrollExample() {
// this will hold the ref to our scroll target, which is just a div that we
// place below our list of recipes to act as a sentinel for scroll intersection
const scrollTargetRef = useRef<HTMLDivElement>(null);
const [getRecipes, recipesResult, isRecipesCallPending] = useGetRecipes();
// anytime our scroll target is intersected for vertical scroll, the hook
// will return true, which is how we know to fetch the next page of recipes
const isScrolling = useInfiniteScroll(scrollTargetRef);
const count = recipesResult?.data?.length ?? -1;
const total = recipesResult?.total ?? 0;
useEffect(() => {
if ((isScrolling && !isRecipesCallPending && count < total) || (!isRecipesCallPending && !recipesResult)) {
getRecipes();
}
}, [count, getRecipes, isRecipesCallPending, isScrolling, recipesResult, total]);
return (
<div>
<h4>
{count && total ? `${count === total ? `All ${count}` : `${count} of ${total}`} recipes retrieved!` : ''}
{count && total && count < total ? ' (scroll recipe list to load more)' : ''}
</h4>
<div style={{ height: '300px', overflowY: 'auto', padding: '1rem', width: '100%' }}>
<ul>{recipesResult?.data?.map((recipe) => <li key={recipe.id}>{recipe.name}</li>)}</ul>
{isRecipesCallPending && <div>Loading recipes...</div>}
<div ref={scrollTargetRef} />
</div>
</div>
);
}
Parameters
Name | Type | Required? | Default | Description |
---|---|---|---|---|
bottomTriggerElement | React.RefObject | yes | - | Holds a ref to an element that acts as sentinel for scroll intersection |
disabled | boolean | no | false | If set to true , the hook will stop detecting scroll |
Returns
Returns boolean
that will be true
when the respective target element is scrolling.