Harnessing the Power of @tanstack/react-virtual with React Hooks: A Step-by-Step Guide
Tags: reactvirtual, react, productivity
Published: 2023-07-19 21:23:52

## Introduction: 

In the realm of web development, optimizing performance and efficiency is key to delivering exceptional user experiences. When dealing with large lists or tables, rendering every item in the DOM can lead to performance bottlenecks and increased memory usage. Thankfully, **[@tanstack/react-virtual](https://www.npmjs.com/package/@tanstack/react-virtual)** comes to the rescue. You can check out the full docs **[here](https://tanstack.com/virtual/v3/docs/guide/introduction)** . In this article, we'll explore what **@tanstack/react-virtual** is, and guide you through using it step by step, empowering you to customize your virtualized components using React Hooks.

### What is @tanstack/react-virtual?

**@tanstack/react-virtual** is a powerful library that enables efficient rendering of large datasets in React applications. By using virtualization techniques, it only renders the items currently visible on the screen, resulting in improved performance, reduced memory consumption, and a smoother user experience.

### Step-by-Step Guide

#### Step 1: Installation

Begin by installing **@tanstack/react-virtual** as a dependency in your React project. You can use any package manager of your choice. However in this article we will go with yarn

```bash
yarn add @tanstack/react-virtual
```

#### Step 2: Importing the Library and React Hooks

After installing the library, import the necessary components and React Hooks into your project. In this example, we'll use the `useVirtualizer` Hook provided by **@tanstack/react-virtual**. Import it alongside the required React modules as shown below:

```ts
import React, { useRef, useEffect } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
```

#### Step 3: Setting up the Virtualized List

Create a functional component and define the necessary state variables. 

```ts
function MyVirtualizedList() {
  const parentRef = React.useRef<HTMLDivElement>(null)
  const [listItems, setListItems] = useState<ListItem[]>([])
}
```

- The `parentRef` is used to reference the scrollable element for the list. 
- The `listItems` is an array of your list which you need to render. 

Next, we will fetch out data from an api for the list items and update our state. This article assumes the fetching, so we will use the function `getListItems()` for that. Our assumption is that the method returns an array of strings. 

Please note the array can be of any type depending on what you need to render.

```ts
 useEffect(()=>{
    const data = getListItems();
    setListItems(data)
  }, [])
```

Next, we will create our virtualization using the hook we had imported earlier as below

```ts
  const virtualizer = useVirtualizer({
    count: listItems.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 35,
  });
```
- The `count` property in `useVirtualizer` specifies the total number of items in the list.
- The `getScrollElement` property is a callback function that returns the reference to the scrollable element. In this example, it is set to `() => parentRef.current` to get the scrollable element from the parentRef useRef hook.
- The `estimateSize` property provides an estimate of the row size in pixels. In this example, it is set to `() => 35`.

Next, we will create our actual component to render the context of the virtualized items

```ts
function MyVirtualizedList() {
// Previous code goes here

  const virtualItems = virtualizer.getVirtualItems();
  const totalSize = virtualizer.getTotalSize();

  return (
    <>
      <div ref={parentRef} className="overflow-auto h-400">
        <div className="relative w-full" style={{ height: `${totalSize}px` }}>
          {virtualItems.map(virtualItem => {
            const listItem = listItems[virtualItem.index];

            return (
              <div
                key={virtualItem.key}
                className="absolute top-0 left-0 w-full"
                style={{
                  height: `${virtualItem.size}px`,
                  transform: `translateY(${virtualItem.start}px)`,
                }}
              >
                Item: {listItem}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}
```

- `getVirtualItems()` method returns an array of virtual items currently visible in the viewport. You can iterate over this array to access and modify individual virtual items.
- `getTotalSize()` method returns the total size in pixels for the virtualized items. This measurement will incrementally change if you choose to dynamically measure your elements as they are rendered.

While rendering we are mapping th virtualItems, then for each virtual items, we select an item from our `listItems` depending on the array of that item. You can then render the item as to your preference and depending on the item structure. In our case the assumption was our list is an array of strings.


#### Step 4: Customizing the List with React Hooks

One of the advantages of using React Hooks is the flexibility to customize your virtualized list. You can modify the state variables, such as `count`, or update the rendering logic based on your requirements. Additionally, you can incorporate other React Hooks, such as `useState` or `useEffect`, to manage additional state or handle side effects.

#### Step 5: Styling and UI Customization

To style your virtualized list, you can use any css library or write your own plain css. In this article however, we chose to use [Tailwind CSS](https://tailwindcss.com/docs/installation). Therefore you can ensure that Tailwind CSS is installed and configured in your project. Then, modify the JSX code to utilize Tailwind CSS classes to your taste:

**Here is the full example**

```ts
import React, { useRef, useEffect } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';

function MyVirtualizedList() {
  const parentRef = React.useRef<HTMLDivElement>(null)
  const [listItems, setListItems] = useState<ListItem[]>([])
 
 useEffect(()=>{
    const data = getListItems();
    setListItems(data)
  }, [])

  const virtualizer = useVirtualizer({
    count: listItems.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 35,
  });

  const virtualItems = virtualizer.getVirtualItems();
  const totalSize = virtualizer.getTotalSize();

  return (
    <>
      <div ref={parentRef} className="overflow-auto h-400">
        <div className="relative w-full" style={{ height: `${totalSize}px` }}>
          {virtualItems.map(virtualItem => {
            const listItem = listItems[virtualItem.index]; 

            return (
              <div
                key={virtualItem.key}
                className="absolute top-0 left-0 w-full"
                style={{
                  height: `${virtualItem.size}px`,
                  transform: `translateY(${virtualItem.start}px)`,
                }}
              >
                Item: {listItem}
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}

```