InfiniteTable
InfiniteTable — preset для длинных списков без пагинации: включает infiniteLoading, подключает scrollRef и IntersectionObserver через onLoadMore / hasMore, по умолчанию включает виртуализацию строк (enableRowVirtualization).
Когда использовать
- Лента записей с подгрузкой при скролле.
- Не нужна постраничная навигация.
Когда не нужен:
- Классическая пагинация —
SimpleTable/ServerTable. - Нужен полный контроль над виртуализацией колонок или кастомными параметрами virtualizer — базовый
Table.
Чтобы отключить виртуализацию строк: enableRowVirtualization={false}.
Примеры использования
Подгрузка при скролле
tsx
import { InfiniteTable, SimpleColumnDef } from '@cloud-ru/ds-table';
import { useCallback, useState } from 'react';
type User = {
id: string;
name: string;
email: string;
role: string;
};
const ALL_USERS: User[] = Array.from({ length: 20 }, (_, index) => ({
id: `u-${index + 1}`,
name: `Пользователь ${index + 1}`,
email: `user${index + 1}@example.com`,
role: index % 2 === 0 ? 'Editor' : 'Viewer',
}));
const columns: SimpleColumnDef<User>[] = [
{ key: 'name', header: 'Имя', width: 200 },
{ key: 'email', header: 'Email', width: 240 },
{ key: 'role', header: 'Роль', width: 140 },
];
const PAGE = 5;
export function InfiniteTableBasic() {
const [items, setItems] = useState(() => ALL_USERS.slice(0, PAGE));
const [loading, setLoading] = useState(false);
const hasMore = items.length < ALL_USERS.length;
const onLoadMore = useCallback(() => {
setLoading(true);
window.setTimeout(() => {
setItems(ALL_USERS.slice(0, Math.min(items.length + PAGE, ALL_USERS.length)));
setLoading(false);
}, 300);
}, [items.length]);
return (
<div style={{ display: 'grid', gridTemplateRows: 'minmax(0, 1fr)', height: 360 }}>
<InfiniteTable
data={items}
columns={columns}
getRowId={user => user.id}
loading={loading}
hasMore={hasMore}
onLoadMore={onLoadMore}
outline
/>
</div>
);
}Через хук useInfiniteTableProps
tsx
import { SimpleColumnDef, Table, useInfiniteTableProps } from '@cloud-ru/ds-table';
import { useCallback, useState } from 'react';
type User = { id: string; name: string; email: string };
const ALL_USERS: User[] = Array.from({ length: 12 }, (_, index) => ({
id: `u-${index + 1}`,
name: `Пользователь ${index + 1}`,
email: `user${index + 1}@example.com`,
}));
const columns: SimpleColumnDef<User>[] = [
{ key: 'name', header: 'Имя', width: 200 },
{ key: 'email', header: 'Email', width: 240 },
];
const PAGE = 4;
export function InfiniteTableWithHook() {
const [items, setItems] = useState(() => ALL_USERS.slice(0, PAGE));
const [loading, setLoading] = useState(false);
const hasMore = items.length < ALL_USERS.length;
const onLoadMore = useCallback(() => {
setLoading(true);
window.setTimeout(() => {
setItems(ALL_USERS.slice(0, Math.min(items.length + PAGE, ALL_USERS.length)));
setLoading(false);
}, 300);
}, [items.length]);
const tableProps = useInfiniteTableProps({
data: items,
columns,
getRowId: user => user.id,
loading,
hasMore,
onLoadMore,
});
return (
<div style={{ display: 'grid', gridTemplateRows: 'minmax(0, 1fr)', height: 360 }}>
<Table {...tableProps} outline />
</div>
);
}Без подгрузки (hasMore: false)
tsx
import { InfiniteTable, SimpleColumnDef } from '@cloud-ru/ds-table';
type User = { id: string; name: string; email: string };
const USERS: User[] = [
{ id: 'u-1', name: 'Анна Иванова', email: 'anna@example.com' },
{ id: 'u-2', name: 'Борис Петров', email: 'boris@example.com' },
];
const columns: SimpleColumnDef<User>[] = [
{ key: 'name', header: 'Имя', width: 200 },
{ key: 'email', header: 'Email', width: 240 },
];
export function InfiniteTableStatic() {
return (
<div style={{ display: 'grid', gridTemplateRows: 'minmax(0, 1fr)', height: 280 }}>
<InfiniteTable data={USERS} columns={columns} getRowId={user => user.id} hasMore={false} outline />
</div>
);
}