import { FlashList, ListRenderItem } from "@shopify/flash-list"; import React, { useCallback, useEffect, useRef, useState } from "react"; import { RefreshControl, Text, View } from "react-native"; import { AsyncContent } from "./AsyncContent"; export type PaginatedFlashListProps = { pageSize?: number; sortingParam?: string; statusParam?: string; estimatedItemSize?: number; fetchFunction: (params: { sortingParam?: string; statusParam?: string; page: number; pageSize: number; }) => Promise; renderItem: ListRenderItem; ListEmptyComponent: | React.ReactElement< unknown, string | React.JSXElementConstructor > | React.ComponentType | undefined; }; const PAGE_SIZE = 10; export function PaginatedFlashList({ pageSize = PAGE_SIZE, sortingParam, statusParam, estimatedItemSize = 120, renderItem, fetchFunction, ListEmptyComponent, }: PaginatedFlashListProps) { const [data, setData] = useState(); const [refreshing] = useState(false); const [loading, setLoading] = useState(false); const pageRef = useRef(0); const hasNextPageRef = useRef(true); const onRefresh = useCallback(() => { setData(undefined); hasNextPageRef.current = true; pageRef.current = 0; onLoad(); }, []); const keyExtractor = useCallback( (item: unknown) => (item as { id: string }).id, [] ); const onEndReached = useCallback(() => onLoad(), []); const onLoad = useCallback(() => { if (loading || !hasNextPageRef.current) return; setLoading(true); fetchFunction({ sortingParam, statusParam, pageSize, page: pageRef.current, }) .then((response) => { hasNextPageRef.current = (response.totalCount || 0) > (pageRef.current + 1) * pageSize; const newData = response.items || []; setData((prevData) => { if (prevData) { return [...prevData, ...newData]; } return newData; }); pageRef.current += 1; }) .catch((error) => { console.error("Error fetching data:", error); }) .finally(() => { setLoading(false); }); }, [fetchFunction, sortingParam, statusParam, loading]); const Separator = useCallback(() => , []); const LoadingFooter = useCallback(() => { if (!loading) return null; return ( Loading more... ); }, [loading]); useEffect(() => { onLoad(); }, []); if (data === undefined) { return ; } return ( } renderItem={renderItem} estimatedItemSize={estimatedItemSize} keyExtractor={keyExtractor} onEndReached={onEndReached} onEndReachedThreshold={0.5} ItemSeparatorComponent={Separator} ListFooterComponent={LoadingFooter} ListEmptyComponent={ListEmptyComponent} /> ); }