in packages/bonito-ui/src/hooks/use-load-more.ts [27:87]
export function useLoadMore<T>(
onLoad: LoadMoreFn<T>,
onLoadError?: (error: unknown) => void
) {
const [items, setItems] = React.useState<T[]>([]);
const [hasMore, setHasMore] = React.useState(true);
const onLoadErrorRef = useRef(onLoadError);
onLoadErrorRef.current = onLoadError;
const pendingPromise = useRef<CancellablePromise<
LoadMoreListResult<T>
> | null>(null);
const loadMore = useCallback(
async (fresh: boolean = false): Promise<void> => {
if (pendingPromise.current) {
return;
}
pendingPromise.current = cancellablePromise(onLoad(fresh));
try {
const { items, done } = await pendingPromise.current;
pendingPromise.current = null;
if (!done && !items.length) {
// no more data, try again
return loadMore();
}
if (done) {
setHasMore(false);
}
setItems((oriItems) => [...oriItems, ...items]);
} catch (error) {
if (!(error instanceof CancelledPromiseError)) {
pendingPromise.current = null;
onLoadErrorRef.current?.(error);
}
}
},
[onLoad]
);
const loadFresh = useCallback(() => {
if (pendingPromise.current) {
pendingPromise.current.cancel();
pendingPromise.current = null;
}
setItems([]);
setHasMore(true);
loadMore(true);
}, [loadMore]);
useEffect(() => {
loadFresh();
}, [loadFresh]);
return {
items,
hasMore,
onLoadMore: loadMore,
onRefresh: loadFresh,
};
}