Skip to content

Instantly share code, notes, and snippets.

@Housi
Last active April 6, 2021 13:42
Show Gist options
  • Save Housi/a32ee26cd92950aae66aecc35894fe52 to your computer and use it in GitHub Desktop.
Save Housi/a32ee26cd92950aae66aecc35894fe52 to your computer and use it in GitHub Desktop.
InfiniteLoader
import React, { ReactElement, useRef, useState, useEffect } from 'react';
type Props = {
pagedData: any;
direction?: 'y' | 'x';
};
export const InfiniteLoader = ({ pagedData, direction = 'y' }: Props): ReactElement | null => {
const [element, setElement] = useState<any>(null);
const prevPos = useRef(-1);
const { data, size, setSize, isValidating } = pagedData;
const loadMore = (): void => {
if (!data || !size || (!data.length && isValidating)) return;
setSize(size + 1);
};
useEffect(() => {
const currentElement = element;
const currentObserver = new IntersectionObserver(
(entries) => {
const firstEntry = entries[0];
const pos = firstEntry.boundingClientRect[direction];
if (prevPos.current > pos || prevPos.current === -1) {
setTimeout(() => loadMore(), 100);
}
prevPos.current = pos;
},
{ threshold: 1 },
);
if (currentElement) {
currentObserver.observe(currentElement);
}
return (): void => {
if (currentElement) {
currentObserver.disconnect();
}
};
}, [element]);
return isValidating ? null : <div ref={setElement} />;
};
@Housi
Copy link
Author

Housi commented Apr 6, 2021

This is solution specific for 'swr' library and their infinite loading solution (https://swr.vercel.app/docs/pagination#use-swr-infinite). Here we use intersection observer to trigger 'load more' whenever our control div enters viewport

so we fetch data like this

    const { data, ...pagedData } = useSWRInfinite(...)

and render it like this

        <Container>
            <SomeTable data={data} ... />
            <InfiniteLoader pagedData={pagedData} />
        </Container>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment