Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/linbudu599/tanstack-virtual-list
Virtual List impl in React, built on @tanstack/react-virtual
https://github.com/linbudu599/tanstack-virtual-list
Last synced: 27 days ago
JSON representation
Virtual List impl in React, built on @tanstack/react-virtual
- Host: GitHub
- URL: https://github.com/linbudu599/tanstack-virtual-list
- Owner: linbudu599
- License: mit
- Created: 2024-01-08T13:26:39.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2024-02-28T09:32:31.000Z (8 months ago)
- Last Synced: 2024-03-29T02:41:21.703Z (7 months ago)
- Language: TypeScript
- Homepage: https://tanstack-virtual-list.vercel.app
- Size: 313 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# tanstack-virtual-list
![NPM Version](https://img.shields.io/npm/v/tanstack-virtual-list)
![NPM (prod) Dependency Version](https://img.shields.io/npm/dependency-version/tanstack-virtual-list/%40tanstack%2Freact-virtual)Ready-to-use virtual list component in React, built on top of [@tanstack/react-virtual](https://tanstack.com/virtual/v3/docs/framework/react/react-virtual), with built-in support for dynamic subitems and infinite loading.
- [Visit live demo here](https://tanstack-virtual-list.vercel.app/)
- [Configurations](#configurations)## Installation
```bash
npm install tanstack-virtual-list
yard add tanstack-virtual-list
pnpm install tanstack-virtual-list
```## Notes
- When using `dynamic` mode, imperative scroll control with `behavior: 'smooth'` doesnot works correctly, and you will see warning in devtool console by `@tanstack/react-virtual`:
> *The `smooth` scroll behavior is not fully supported with dynamic size.`*
- When using `dynamic` mode, infinite list can not works correctly as element rect meaturement failed.
## Usage
The `tanstack-virtual-list` package is as consistent as possible with the API of `@tanstack/react-virtual`, but has additional dataSource and renderItem properties for rendering list elements, plus you can provide additional properties directly to the useVirtualizer via `props.useVirtualizerOptions` to provide additional properties directly to the core method useVirtualizer.
```tsx
import React from 'react';
import VirtualList from 'tanstack-virtual-list';const DataSource = Array.from({ length: 1000 }).map((_, i) => i);
export default function App() {
return (
<>
50}
getItemKey={(item, index) => item}
useVirtualizerOptions={{
// ...
}}
renderItem={(item, index) => {
return (
ITEM {item}
);
}}
/>
>
);
}
```## Dynamic Virtual List
The `tanstack-virtual-list` package provides support for **virtual list with subitems of variable height** via `props.dynamic`. Internally, `tanstack-virtual-list` renders the list using the specialized `DynamicVirtualList`, which has a slightly different layout and configuration of the list, list container, and subitem containers, as compared to when the list is using fixed height.
```tsx
import React from 'react';
import VirtualList from 'tanstack-virtual-list';const DataSource = Array.from({ length: 1000 }).map((_, i) => ({
id: i,
text: Array.from(
{
length: Math.floor(Math.random() * 7) + 2,
},
(_, index) =>ITEM {i}
),
}));export default function App() {
return (
<>
60}
dataSource={DataSource}
getItemKey={(item, index) => item.id}
renderItem={(item, index) => {
return (
{item.text}
);
}}
/>
>
);
}```
## Infinite Loading
To simplify the use in infinite loading scenarios, `tanstack-virtual-list` provides a `` component, which is a simple wrapper based on `IntersectionObserver`, and you can trigger the behavior of loading the next page of data through its `onAppear` event.
```tsx
import React, { useEffect, useState } from 'react';
import VirtualList, { Loader } from 'tanstack-virtual-list';export default function App() {
const [pageNo, setPageNo] = useState(0);
const [fetchingNextPage, setFetchingNextPage] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [hasNextPage, setHasNextPage] = useState(true);const fetchNextPage = async (pageNo = 0) => {
console.log('Fetching', pageNo);
setFetchingNextPage(true);
const res = await mockRequest(pageNo);
console.log('√ Fetched', pageNo);setFetchingNextPage(false);
setDataSource([...dataSource, ...res.data.data]);
setHasNextPage(res.data.hasNext);
};useEffect(() => {
if (fetchingNextPage || !hasNextPage) return;
fetchNextPage(pageNo);
}, [pageNo]);const handleLoaderAppear = () => {
console.log('Loader appears, fetching next page...');
setPageNo((no) => no + 1);
};return (
<>
{dataSource.length ? (
50}
overscan={5}
dataSource={dataSource.concat(['_Loader_'])}
getItemKey={(item, index) => item}
renderItem={(item, index) => {
const isLoaderItem = index > dataSource.length - 1;return (
{isLoaderItem ? (
<>
{hasNextPage ? 'Loading more...' : 'Nothing more to load'}
>
) : (
{item}
)}
);
}}
/>
) : null}
>
);
}
```In this example we place `` in the last position of data sources(by `dataSource.concat(['_Loader_'])`),and render `` in `renderItem` function. You can also place it in anywhere you like.
## Configurations
`tanstack-virtual-list` preserves serveral properties from `useVirtualizer` param, and, to prevent unknown DOM properties error, less commonly used properties will be placed in `useVirtualizerOptions`.
### `dataSource`
- `T[]`
- **Required**The data source to render list items.
`tanstack-virtual-list` provides first-level typescript support, as it infers type of data item from `dataSource`.### `renderItem`
- `(item: T, index: number, virtualItem: VirtualItem) => React.ReactNode`
- **Required**Specify how to render item.
### `getItemHeight`
- `(item: TDataSource, index: number) => number`
- **Required**Specify how to calculate item height.
This is also required when using `dynamic` mode as initial rect provider.
### `getItemKey`
- `(item: TDataSource, index: number) => React.Key`
- `default: (item, index) => index`Specify how to get item's key.
If not specified, `tanstack-virtual-list` use item index as fallback.
### `dynamic`
- `boolean`
- `default: false`Whether to enable dynamic mode.
Dynamic mode using a complete different layout compared to fixed mode, so make sure you need to use it indeed.
This is not a natively provided configuration, but used by `tanstack-virtual-list` it self.
### `horizontal`
- `boolean`
- `default: false`Whether to use horizontal layout.
See [virtualizer#horizontal](https://tanstack.com/virtual/v3/docs/api/virtualizer#horizontal) for details.
### `overscan`
- `number`
- `default: 0`See [virtualizer#overscan](https://tanstack.com/virtual/v3/docs/api/virtualizer#overscan) for details.
### `initialOffset`
- `number`
- `default: 0`See [virtualizer#initialoffset](https://tanstack.com/virtual/v3/docs/api/virtualizer#initialoffset) for details.
### `prefixClassName`
- `string`
- `default: 'tanstack-virtual-list'`This attribute is used internally in the component to determine the class name of layout containers, like:
- `div.tanstack-virtual-list-container`
- `div.tanstack-virtual-list-content`
- `div.tanstack-virtual-list-item`
- `div.tanstack-virtual-list-item`
- `div.tanstack-virtual-list-item`
- ...### `padding`
- `number | [start?: number, end?: number]`
- `default: 0`A shortcut for [virtualizer#paddingstart](https://tanstack.com/virtual/v3/docs/api/virtualizer#paddingstart) | [virtualizer#paddingend](https://tanstack.com/virtual/v3/docs/api/virtualizer#paddingend) .
- `input: 10` → `output: [10, 10]`
- `input: [10, 20]` → `output: [10, 20]`### `scrollPadding`
Nearly same to [padding](#padding).
See [virtualizer#scrollpaddingstart](https://tanstack.com/virtual/v3/docs/api/virtualizer#scrollpaddingstart) | [virtualizer#scrollpaddingend](https://tanstack.com/virtual/v3/docs/api/virtualizer#scrollpaddingend) for more details.
## `useVirtualizerOptions`
See [Virtualizer](https://tanstack.com/virtual/v3/docs/api/virtualizer) here for more configurations on `@tanstack/react-virtual`.
## Ref
`tanstack-virtual-list` provides ref expose and corresponding typing:
```typescript
import React, { useRef } from 'react';import VirtualList, { type VirtualListRef } from tanstack-virtual-list';
export default function App() {
const ref = useRef(null);const scrollTo20 = () => {
ref.current?.scrollToIndex(20);
};return (
;
<>
50}
dataSource={DataSource}
renderItem={(item, index) => {
return
}}
/>
>
);
}
```