Skip to content

useVirtualList

Category
Export Size
1.13 kB
Last Changed
5 days ago

Create virtual lists with ease. Virtual lists (sometimes called virtual scrollers) allow you to render a large number of items performantly. They only render the minimum number of DOM nodes necessary to show the items within the container element by using the wrapper element to emulate the container element's full height.

WARNING

Consider using @tanstack/react-virtual instead, if you are looking for more features.

Demo

Usage

Simple list

tsx
import { 
useVirtualList
} from '@reause/core'
const {
list
,
containerProps
,
wrapperProps
} =
useVirtualList
(
Array
.
from
(
Array
.
from
({
length
: 99999 }).
keys
()),
{ // Keep `itemHeight` in sync with the item's row.
itemHeight
: 22,
}, )
tsx
<
div
{...containerProps} style={{ ...containerProps.style, height: '300px' }}>
<
div
{...wrapperProps}>
{
list
.map(
item
=> (
// `item` is `{ data, index }` — `index` is the absolute index <
div
key={
item
.index} style={{
height
: 22 }}>
Row: {' '} {item.data} </div> ))} </div> </div>

Config

StateTypeDescription
itemHeightnumberensure that the total height of the wrapper element is calculated correctly.*
itemWidthnumberensure that the total width of the wrapper element is calculated correctly.*
overscannumbernumber of pre-rendered DOM nodes. Prevents whitespace between items if you scroll very quickly.

* The itemHeight or itemWidth must be kept in sync with the height of each row rendered. If you are seeing extra whitespace or jitter when scrolling to the bottom of the list, ensure the itemHeight or itemWidth is the same height as the row.

Source Forms

list is a read-only value source and takes a plain readonly T[]. Resolve a React ref or state value at the call site:

tsx
const [
items
,
setItems
] =
useState
(allItems)
const {
list
} =
useVirtualList
(
items
, {
itemHeight
: 22 })
const {
list
:
refList
} =
useVirtualList
(itemsRef.current, {
itemHeight
: 22 })

Reactive list

tsx
import { 
useVirtualList
} from '@reause/core'
import {
useMemo
,
useState
} from 'react'
const
allItems
=
Array
.
from
(
Array
.
from
({
length
: 99999 }).
keys
())
const [
showEven
,
setShowEven
] =
useState
(true)
const
filteredList
=
useMemo
(() =>
allItems
.
filter
(
i
=> (
showEven
?
i
% 2 === 0 :
i
% 2 === 1)), [
showEven
])
const {
list
,
containerProps
,
wrapperProps
} =
useVirtualList
(
filteredList
,
{
itemHeight
: 22 },
)

Horizontal list

tsx
import { 
useVirtualList
} from '@reause/core'
const
allItems
=
Array
.
from
(
Array
.
from
({
length
: 99999 }).
keys
())
const {
list
,
containerProps
,
wrapperProps
} =
useVirtualList
(
allItems
,
{
itemWidth
: 200 },
)
tsx
<
div
{...containerProps} style={{ ...containerProps.style, height: '300px' }}>
<
div
{...wrapperProps}>
{
list
.map(
item
=> (
<
div
key={
item
.index} style={{
width
: 200 }}>
Row: {' '} {item.data} </div> ))} </div> </div>

Scrolling to a specific item

scrollTo(index, options?) scrolls the container so the item at index becomes visible, supporting behavior ('auto' | 'smooth'), block (vertical alignment: 'start' | 'center' | 'end' | 'nearest') and inline (horizontal alignment).

Type Declarations

Toggle
ts
export interface UseHorizontalVirtualListOptions extends UseVirtualListOptionsBase {
    itemWidth: UseVirtualListItemSize;
}

export interface UseVerticalVirtualListOptions extends UseVirtualListOptionsBase {
    itemHeight: UseVirtualListItemSize;
}

export interface UseVirtualListOptionsBase {
    overscan?: number;
}

export type UseVirtualListOptions = UseHorizontalVirtualListOptions | UseVerticalVirtualListOptions

export interface UseVirtualListItem<T> {
    data: T;
    index: number;
}

export interface UseVirtualListScrollToOptions {
    behavior?: ScrollBehavior;
    block?: ScrollLogicalPosition;
    inline?: ScrollLogicalPosition;
}

export interface UseVirtualListReturn<T> {
    list: UseVirtualListItem<T>[];
    scrollTo: (index: number, options?: UseVirtualListScrollToOptions) => void;
    containerProps: {
        ref: (element: HTMLElement | null) => void;
        onScroll: () => void;
        style: CSSProperties;
    };
    wrapperProps: {
        style: CSSProperties;
    };
}

type UseVirtualListItemSize = number | ((index: number) => number)

export function useVirtualList<T = any>(list: readonly T[], options: UseVirtualListOptions): UseVirtualListReturn<T>

Source

Source · Demo · VueUse

Contributors

hairyf

Changelog

v0.1.0 on
6c0e4 - fix(core): resolve useVirtualList audit findings (#678)
8fddc - chore!: remove all Vue-only Maybe* types and getter unions, adopt React Ref (#462)

Released under the MIT License. v0.1.8