> Leaf UI 0.8.1 · Package: @ifhover/leaf-ui · Source: 435bab23cad7d343653d9b63b049c0b0601eeefb
> Browser documentation: https://ifhover.github.io/leaf-ui/components/infinite-scroll.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/llms-full.txt.

# InfiniteScroll 无限滚动

浏览到列表末尾时加载更多内容。

## 基本用法


项目 1

项目 2

项目 3

项目 4

项目 5

项目 6

项目 7

项目 8

项目 9

项目 10

basic.tsx

复制代码

```tsx lineNumbers file="../../src/examples/infinite-scroll/basic.tsx"
import { InfiniteScroll, ScrollArea } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function InfiniteScrollBasic() {
  const root = useRef<HTMLDivElement>(null);
  const [items, setItems] = useState(() => Array.from({ length: 10 }, (_, i) => i));
  return (
    <ScrollArea ref={root} height={240} aria-label="动态列表">
      <InfiniteScroll
        dataLength={items.length}
        hasMore={items.length < 40}
        target={() => root.current}
        onLoadMore={async (signal) => {
          await new Promise((resolve) => setTimeout(resolve, 500));
          if (!signal.aborted)
            setItems((previous) => [
              ...previous,
              ...Array.from({ length: 10 }, (_, index) => previous.length + index),
            ]);
        }}
      >
        {items.map((item) => (
          <div key={item} style={{ padding: '12px 16px' }}>
            项目 {item + 1}
          </div>
        ))}
      </InfiniteScroll>
    </ScrollArea>
  );
}
```

展开代码

## 更多用法


记录 1

记录 2

记录 3

记录 4

记录 5

记录 6

advanced.tsx

复制代码

```tsx lineNumbers file="../../src/examples/infinite-scroll/advanced.tsx"
import { InfiniteScroll, ScrollArea } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function InfiniteScrollRetry() {
  const root = useRef<HTMLDivElement>(null);
  const attempt = useRef(0);
  const [items, setItems] = useState([0, 1, 2, 3, 4, 5]);
  return (
    <ScrollArea ref={root} height={180} aria-label="重试示例">
      <InfiniteScroll
        dataLength={items.length}
        hasMore={items.length < 12}
        target={() => root.current}
        onLoadMore={async (signal) => {
          await new Promise((resolve) => setTimeout(resolve, 300));
          if (signal.aborted) return;
          if (attempt.current++ === 0) throw new Error('Retry demo');
          setItems((previous) => [...previous, ...[6, 7, 8, 9, 10, 11]]);
        }}
      >
        {items.map((item) => (
          <p key={item}>记录 {item + 1}</p>
        ))}
      </InfiniteScroll>
    </ScrollArea>
  );
}
```

展开代码

## 使用说明

onLoadMore 返回 Promise，一次请求期间不会重复触发。追加新数据后更新 dataLength。signal 在卸载时取消请求，失败后可重试。

## 类型

组装数据、定义回调和使用 ref 时，可以导入这些类型。

```ts
import type { InfiniteScrollProps } from '@ifhover/leaf-ui';
```

## InfiniteScrollProps API

| 属性           | 类型                                       | 默认值   | 说明                 |
| ------------ | ---------------------------------------- | ----- | ------------------ |
| `dataLength` | `number`                                 | 必填    | 已加载数量，变化后允许下一次请求   |
| `hasMore`    | `boolean`                                | 必填    | 还有后续数据             |
| `onLoadMore` | `(signal: AbortSignal) => Promise<void>` | 必填    | 加载更多，signal 用于取消请求 |
| `target`     | `() => HTMLElement \| null`              | —     | 滚动目标或链接打开方式        |
| `threshold`  | `number`                                 | `200` | 距离末尾触发加载的像素距离      |
| `loader`     | `ReactNode`                              | —     | 加载占位内容             |
| `endMessage` | `ReactNode`                              | —     | 全部加载后的内容           |
| `onError`    | `(error: unknown) => void`               | —     | 异常回调               |
