useInfiniteScroll
useInfiniteScroll encapsulates the common infinite scroll logic.
Overview
useInfiniteScroll encapsulates the common infinite scroll logic.
Installation
Open inpnpm dlx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.jsonnpx shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.jsonyarn shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.jsonbun shadcn@latest add https://shadcn-ahooks.vercel.app/r/useInfiniteScroll.jsonuseInfiniteScroll encapsulates the common infinite scroll logic.
const { data, loading, loadingMore, loadMore } = useInfiniteScroll(service);The first parameter service of useInfiniteScroll is an asynchronous function. The input and output parameters of this function have the following conventions:
- The data returned by
servicemust contain alistarray, the type is{ list: any[], ...rest } - The input parameter of
serviceis the latest mergeddata
If the data returned for the first request is { list: [1, 2, 3], nextId: 4 }, the data returned for the second time is { list: [4, 5, 6], nextId: 7 } , then we will automatically merge list, and the merged data will be { list: [1, 2, 3, 4, 5, 6], nextId: 7 }.
Basic usage
In the first example, we demonstrate the implementation of a most basic infinite scroll.
Pagination
In the data fixation scenario, we sometimes use page and pageSize to request new data.
Scrolling to automatically load
In the infinite scrolling scenario, the most common case is to automatically load when scrolling to the bottom. By configuring the following properties, you can achieve scrolling to automatically load.
options.targetspecifies the parent element, The parent element needs to set a fixed height and support internal scrollingoptions.isNoMoredetermines if there is no more dataoptions.directiondetermines the direction of scrolling, the default isbottom
the scroll to bottom demo
the scroll to top demo
Data reset
The data can be reset by reload. The following example shows that after the filter changes, the data is reset to the first page.
The above code can be implemented with reloadDeps syntax sugar. When reloadDeps changes, reload will be triggered automatically.
const result = useInfiniteScroll(service, {
reloadDeps: [keyword]
});Data mutation
With mutate, we can directly modify the current data. The following example demonstrates deleting a record from the data.
API
export type Data = { list: any[];[key: string]: any; };
export type Service<TData extends Data> = (currentData?: TData) => Promise<TData>;
const {
data: TData;
loading: boolean;
loadingMore: boolean;
error?: Error;
noMore: boolean;
loadMore: () => void;
loadMoreAsync: () => Promise<TData>;
reload: () => void;
reloadAsync: () => Promise<TData>;
cancel: () => void;
mutate: (data?: TData) => void;
} = useInfiniteScroll<TData extends Data>(
service: (currentData?: TData) => Promise<TData>,
{
target?: BasicTarget;
isNoMore?: (data?: TData) => boolean;
threshold?: number;
manual?: boolean;
reloadDeps?: DependencyList;
onBefore?: () => void;
onSuccess?: (data: TData) => void;
onError?: (e: Error) => void;
onFinally?: (data?: TData, e?: Error) => void;
}
);Result
| Property | Description | Type |
| - | - | |
| data | The data returned by the service, where the list attribute is the aggregated data | TData | undefined |
| loading | Is the first request in progress | boolean |
| loadingMore | Is more data request in progress | boolean |
| noMore | Whether there is no more data, it will take effect after configuring options.isNoMore | boolean |
| error | Request error message | Error |
| loadMore | Load more data, it will automatically catch the exception, and handle it through options.onError | () => void |
| loadMoreAsync | Load more data, which is consistent with the behavior of loadMore, but returns Promise, so you need to handle the exception yourself | () => Promise<TData> |
| reload | Load the first page of data, it will automatically catch the exception, and handle it through options.onError | () => void |
| reloadAsync | Load the first page of data, which is consistent with the behavior of reload, but returns Promise, so you need to handle the exception yourself | () => Promise<TData> |
| mutate | Modify data directly | (data?: TData) => void |
| cancel | Ignore the current promise response | () => void |
Options
| Property | Description | Type | Default |
| - | ----- |
| target | specifies the parent element. If it exists, it will trigger the loadMore when scrolling to the bottom. Needs to work with isNoMore to know when there is no more data to load. when target is document, it is defined as the entire viewport | () => Element | Element | MutableRefObject<Element> | - |
| isNoMore | determines if there is no more data, the input parameter is the latest merged data | (data?: TData) => boolean | - |
| threshold | The pixel threshold to the bottom for the scrolling to load | number | 100 |
| direction | The direction of the scrolling | bottom |top | bottom |
| reloadDeps | When the content of the array changes, reload will be triggered | any[] | - |
| manual |
- The default is
false. That is, the service is automatically executed during initialization. - If set to
true, you need to manually callrunorrunAsyncto trigger execution
boolean | false |
| onBefore | Triggered before service execution | () => void | - |
| onSuccess | Triggered when service resolve | (data: TData) => void | - |
| onError | Triggered when service reject | (e: Error) => void | - |
| onFinally | Triggered when service execution is complete | (data?: TData, e?: Error) => void | - |useInViewport
Observe whether the element is in the visible area, and the visible area ratio of the element. More information refer to [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
useInterval
A hook that handles the setInterval timer function.