Skip to content

Instantly share code, notes, and snippets.

@potat-dev
Last active June 26, 2024 14:21
Show Gist options
  • Save potat-dev/31f574d2ca53f32d64d817287ce90a91 to your computer and use it in GitHub Desktop.
Save potat-dev/31f574d2ca53f32d64d817287ce90a91 to your computer and use it in GitHub Desktop.
Infinite scrolling list with plain Mantine
import { ReactNode, useEffect, useRef, useState } from 'react';
import { ScrollArea, Box, Text, Badge, Card, Group } from '@mantine/core';
interface InfiniteScrollAreaProps {
items: string[]; // Adjust the type based on the actual item structure
fetchMoreData: () => Promise<void>;
loader: ReactNode;
}
const InfiniteScrollArea: React.FC<InfiniteScrollAreaProps> = ({
items,
fetchMoreData,
loader,
}) => {
const [loading, setLoading] = useState(false);
const viewport = useRef<HTMLDivElement>(null);
const handleScroll = () => {
if (viewport.current) {
const { scrollTop, scrollHeight, clientHeight } = viewport.current;
if (scrollTop + clientHeight >= scrollHeight - 20) {
if (!loading) {
setLoading(true);
fetchMoreData().finally(() => setLoading(false));
}
}
}
};
useEffect(() => {
const currentViewport = viewport.current;
if (currentViewport) {
currentViewport.addEventListener('scroll', handleScroll);
}
return () => {
if (currentViewport) {
currentViewport.removeEventListener('scroll', handleScroll);
}
};
}, [loading]);
return (
<ScrollArea style={{ height: '200px' }} viewportRef={viewport}>
{items.map((item, i) => (
<Card key={i} shadow="sm" padding="md" radius="md" mb="md" withBorder>
<Group justify="space-between" mb="xs">
<Text fw={500}>{item}</Text>
<Badge color="pink">Test</Badge>
</Group>
<Text size="sm" c="dimmed">
With Fjord Tours you can explore more of the magical fjord landscapes with tours and
activities on and around the fjords of Norway
</Text>
</Card>
))}
{loading && (
<Box style={{ display: 'flex', justifyContent: 'center', padding: '4px' }}>{loader}</Box>
)}
</ScrollArea>
);
};
export default InfiniteScrollArea;
import React, { useState } from 'react';
import { Loader } from '@mantine/core';
import InfiniteScrollArea from './InfiniteList';
const ExampleList: React.FC = () => {
const [items, setItems] = useState<string[]>(
Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`)
);
const fetchMoreData = () =>
new Promise<void>((resolve) => {
setTimeout(() => {
setItems((prevItems) => [
...prevItems,
...Array.from({ length: 20 }, (_, i) => `Item ${prevItems.length + i + 1}`),
]);
resolve();
}, 1500);
});
return (
<InfiniteScrollArea items={items} fetchMoreData={fetchMoreData} loader={<Loader size="sm" />} />
);
};
export default ExampleList;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment