Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/react/VList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface VListProps
| "onScroll"
| "onScrollEnd"
| "keepMounted"
| "renderPlaceholders"
>,
ViewportComponentAttributes {
/**
Expand Down Expand Up @@ -57,6 +58,7 @@ export const VList = forwardRef<VListHandle, VListProps>(
onScroll,
onScrollEnd,
style,
renderPlaceholders,
...attrs
},
ref
Expand All @@ -79,6 +81,7 @@ export const VList = forwardRef<VListHandle, VListProps>(
item={item}
onScroll={onScroll}
onScrollEnd={onScrollEnd}
renderPlaceholders={renderPlaceholders}
>
{children}
</Virtualizer>
Expand Down
41 changes: 24 additions & 17 deletions src/react/Virtualizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ export interface VirtualizerProps {
* Elements rendered by this component.
*
* You can also pass a function and set {@link VirtualizerProps.count} to create elements lazily.
* Placeholder will be true for out of view elements when renderPlaceholders is turned on, otherwise placeholder is always false.
*/
children: ReactNode | ((index: number) => ReactElement);
children: ReactNode | ((index: number, placeholder: boolean) => ReactElement);
/**
* If you set a function to {@link VirtualizerProps.children}, you have to set total number of items to this prop.
*/
Expand All @@ -114,6 +115,10 @@ export interface VirtualizerProps {
* - If set, you can opt out estimation and use the value as initial item size.
*/
itemSize?: number;
/**
* Render placeholders, allows for a placeholder element to be rendered instead of nothing when out of view
*/
renderPlaceholders?: boolean;
/**
* While true is set, scroll position will be maintained from the end not usual start when items are added to/removed from start. It's recommended to set false if you add to/remove from mid/end of the list because it can cause unexpected behavior. This prop is useful for reverse infinite scrolling.
*/
Expand Down Expand Up @@ -183,6 +188,7 @@ export const Virtualizer = forwardRef<VirtualizerHandle, VirtualizerProps>(
ssrCount,
as: Element = "div",
item: ItemElement = "div",
renderPlaceholders = false,
scrollRef,
onScroll: onScrollProp,
onScrollEnd: onScrollEndProp,
Expand Down Expand Up @@ -238,8 +244,8 @@ export const Virtualizer = forwardRef<VirtualizerHandle, VirtualizerProps>(

const items: ReactElement[] = [];

const getListItem = (index: number) => {
const e = getElement(index);
const getListItem = (index: number, placeholder = false) => {
const e = getElement(index, placeholder);

return (
<ListItem
Expand Down Expand Up @@ -327,24 +333,25 @@ export const Virtualizer = forwardRef<VirtualizerHandle, VirtualizerProps>(
};
}, []);

const mounted = new Set(keepMounted || []);
for (let i = 0, j = startIndex; i < j; i++) {
if (mounted.has(i)) {
items.push(getListItem(i));
} else if (renderPlaceholders) {
items.push(getListItem(i, true));
}
}

for (let i = startIndex, j = endIndex; i <= j; i++) {
items.push(getListItem(i));
}

if (keepMounted) {
const startItems: ReactElement[] = [];
const endItems: ReactElement[] = [];
sort(keepMounted).forEach((index) => {
if (index < startIndex) {
startItems.push(getListItem(index));
}
if (index > endIndex) {
endItems.push(getListItem(index));
}
});

items.unshift(...startItems);
items.push(...endItems);
for (let i = endIndex + 1, j = count; i < j; i++) {
if (mounted.has(i)) {
items.push(getListItem(i));
} else if (renderPlaceholders) {
items.push(getListItem(i, true));
}
}

return (
Expand Down
2 changes: 1 addition & 1 deletion src/react/WindowVirtualizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export const WindowVirtualizer = forwardRef<
}, []);

for (let i = startIndex, j = endIndex; i <= j; i++) {
const e = getElement(i);
const e = getElement(i, false);
items.push(
<ListItem
key={getKey(e, i)}
Expand Down
4 changes: 2 additions & 2 deletions src/react/useChildren.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { ItemElement, flattenChildren } from "./utils";
* @internal
*/
export const useChildren = (
children: ReactNode | ((i: number) => ReactElement),
children: ReactNode | ((i: number, placeholder: boolean) => ReactElement),
count: number | undefined
) => {
return useMemo((): [(i: number) => ItemElement, number] => {
return useMemo((): [(i: number, placeholder: boolean) => ItemElement, number] => {
if (typeof children === "function") {
return [children, count || 0];
}
Expand Down