I'd say that the only to solve your problem would be to measure the size of content with useLayoutEffect, and then to 'split' said content into pages.
(This is because I'm assuming you don't know the size of the each item from the list - if you did it would be simpler!).
I'd start with a useComponentSize hook that would look something like so:
// Adapted from: https://stackoverflow.com/a/57272554/6595024
const useComponentSize = () => {
const informParentOfHeightChange = useContext<(h: number) => void>(
UpdateParentAboutMyHeight
);
const targetRef = useRef();
useLayoutEffect(() => {
if (targetRef.current) {
informParentOfHeightChange(targetRef.current.offsetHeight);
}
return () => informParentOfHeightChange(0);
}, [informParentOfHeightChange]);
return targetRef;
};
const UpdateParentAboutMyHeight = /* Left as an exercise to the reader */
Note: That my implementation is rather 'basic'; you'd probably want to useTransition or some other type of debounce effect so your UI wouldn't slow down to a crawl
Using this hook, the child would be able to inform the parent whenever it's height changed.
Here's an example:
const Comp = () => {
const targetRef = useComponentSize();
return <div ref={targetRef}>{/* etc */}</div>;
};
So then 'all' you'd need to do is create a parent component that keeps track of the height of all of it's Comp children.
Here's some (inefficient) pseudo code to help you get an idea:
const UpdateParentAboutMyHeightProvider = /* Left as an exercise to the reader */
const HEIGHT_PER_PAGE = 1000;
const PageLayout = ({ items_to_render }: { items_to_render: Comp[] }) => {
const [items, setItems] = useState<{ height: number }[]>([]);
let curHeight = 0;
let curPage = 0;
const pages = items_to_render.reduce((pageList, item, index) => {
const itemHeight = items[index].height;
if (curHeight + itemHeight >= HEIGHT_PER_PAGE) {
// Create a new page!
pageList.push([item]);
curHeight = itemHeight;
curPage += 1;
return pageList;
}
// Add to existing page!
curHeight += itemHeight;
pageList[curPage].push(item);
return pageList;
}, [] as Array<Array<Comp>>);
return (
<UpdateParentAboutMyHeightProvider value={setItems}>
{pages.map((page, number) => (
<Page number={number + 1} key={number}>{page.map((item) => item)}</Page>
))}
</UpdateParentAboutMyHeightProvider>
);
};
I'll repeat that the implementation I wrote here is very basic and inefficient; the logic for when a page would be bigger than the maximum size is also probably insufficient[1]
Hopefully it'll be helpful in pointing you in the right direction.
[1] I kept it simple for readability and because I don't know your particular use case