npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

virtualize-it

v1.1.2

Published

This project provides virtualized list and grid components for efficient rendering of large datasets.

Downloads

80

Readme

Virtualized List and Grid Component

This project provides virtualized list and grid components for efficient rendering of large datasets.

It provides the following components:

  • FixedList: A list component that renders items of a fixed height/width.
  • DynamicList: A list component that renders items of varying heights/widths.
  • VirtualizedGrid: A grid component that renders a large number of rows and columns efficiently.

Contents

FixedList

FixedListProps

| Prop | Type | Default | Description | Required | | ------------- | ------------------------- | ---------- | ------------------------------------------------------------ | -------- | | children | JSX.Element[] | - | The children to render in the list | ✓ | | totalElements | number | - | The total number of elements in the list | ✓ | | width | number | "100%" | The width of the container | | | height | number | "100%" | The height of the container | | | overscanCount | number | 3 | The number of elements to render outside of the visible area | | | gap | number | 0 | The gap between each item in the list | | | itemSize | number | - | The size of each item in the list | | | orientation | "vertical" | "horizontal | "vertical" | The orientation of the list | | | reverse | boolean | false | Indicates if the list should start at the bottom | |

FixedList - Usage

The FixedList component is used to render a list of items where each item has a fixed height/width. It can be an horizontal or vertical list. The itemSize prop is required when using the FixedList component. The itemSize prop specifies the height or width (depending on the orientation) of each item in the list.

import { FixedList } from "virtualize-it";
import { ChildComponentProps } from "./types";

function ChildComponent(props: ChildComponentProps) {
  return (
    <div
      style={{
        height: "100px",
        width: "100%",
      }}
    >
      <h1>{props.title}</h1>
      <p>{props.description}</p>
    </div>
  );
}

function MainComponent() {
  return (
    <div className='w-full h-full'>
      <FixedList
        totalElements={100}
        itemSize={100}
        overscanCount={3}
        gap={10}
        orientation='vertical'
      >
        {Array.from({ length: 100 }).map((item, index) => (
          <ChildComponent
            key={item.id} // IMPORTANT: use a consistent key for each item, don't use the index.
            title={`Title ${index}`}
            description={`Description ${index}`}
          />
        ))}
      </FixedList>
    </div>
  );
}

DynamicListProps

DynamicListProps

| Prop | Type | Default | Description | Required | | ------------- | ------------- | ---------- | ------------------------------------------------------------ | -------- | | children | JSX.Element[] | - | The children to render in the list | ✓ | | totalElements | number | - | The total number of elements in the list | ✓ | | getItemSize | function | - | A function that returns the size of each item | ✓ | | width | number | "100%" | The width of the container | | | height | number | "100%" | The height of the container | | | overscanCount | number | 3 | The number of elements to render outside of the visible area | | | gap | number | 0 | The gap between each item in the list | | | orientation | string | "vertical" | The orientation of the list | | | reverse | boolean | false | Indicates if the list should start at the bottom | |

DynamicList - Usage

The DynamicList component is used to render a list of items where each item has a varying height/width. It can be an horizontal or vertical list. It is thinked to be used in list where the items have different heights/widths based on the type or content of the item. The getItemSize prop is required when using the DynamicList component. It is a function that receives the index of the item as an argument and returns the height or width (depending on the orientation) of each item in the list.

import { DynamicList } from "virtualize-it";
import { useCallback } from "react";

const data = [
  {
    id: 1,
    type: "text",
    content: "This is a text item",
  },
  {
    id: 2,
    type: "image",
    content: "https://example.com/image.jpg",
  },
  {
    id: 3,
    type: "text",
    content: "This is another text item",
  },
];

const sizeMap = {
  text: 100,
  image: 200,
};

function ChildComponent(props) {
  return (
    <div
      style={{
        height: "100px",
        width: "100%",
      }}
    >
      {props.type === "image" && <img src={props.content} alt='image' />}

      {props.type === "text" && <h1>{props.content}</h1>}
    </div>
  );
}

function MainComponent() {
  const getItemSize = useCallback((index: number) => {
    // NOTE: consider memoizing this function if it will not change frequently.
    const item = data[index];

    return sizeMap[item.type];
  }, []);

  return (
    <div className='w-full h-full'>
      <DynamicList
        totalElements={data.length}
        getItemSize={getItemSize}
        overscanCount={1}
        gap={10}
      >
        {data.map((item, index) => (
          <ChildComponent
            key={item.id} // IMPORTANT: use a consistent key for each item, don't use the index.
            type={item.type}
            content={item.content}
          />
        ))}
      </DynamicList>
    </div>
  );
}

VirtualizedGrid

VirtualizedGridProps

| Prop | Type | Default | Description | Required | | ------------------- | ------ | ------- | ----------------------------------------------------------- | -------- | | rowHeight | number | - | The height of each row in the grid | ✓ | | columnWidth | number | - | The width of each column in the grid | | | totalRows | number | - | The total number of rows in the grid | ✓ | | totalColumns | number | - | The total number of columns in the grid | | | width | number | "100%" | The width of the container | | | height | number | "100%" | The height of the container | | | rowOverscanCount | number | 3 | The number of rows to render outside of the visible area | | | columnOverscanCount | number | 3 | The number of columns to render outside of the visible area | | | rowGap | number | 0 | The gap between each row in the grid | | | columnGap | number | 0 | The gap between each column in the grid | |

VirtualizedGrid - Usage

The VirtualizedGrid component is used to render a grid of items where each item has a fixed height/width. The children of the VirtualizedGrid component should be a 2D array where each element in the outer array represents a row and each element in the inner array represents a column.

If the totalColumns or columnWidth props are not provided the component will behave as a FixedList. Also if the children of each row element are not an array the component will behave as a FixedList.

import { VirtualizedGrid } from "virtualize-it";

const data = Array.from({ length: 1000 }).map((_, index) => ({
  id: index,
  title: `Title ${index}`,
  description: `Description ${index}`,
  items: Array.from({ length: 10 }).map((_, index) => ({
    id: index,
    title: `Item ${index}`,
  })),
}));

function MainComponent() {
  return (
    <div className='w-full h-full'>
      <VirtualizedGrid
        totalRows={data.length}
        totalColumns={10}
        rowHeight={100}
        columnWidth={100}
        rowOverscanCount={3}
        columnOverscanCount={3}
        rowGap={10}
        columnGap={10}
      >
        {data.map((row, rowIndex) => (
          <div key={row.id} className='flex flex-col'>
            {row.items.map((item, itemIndex) => (
              <div key={item.id} className='flex flex-col'>
                <h1>{item.title}</h1>
              </div>
            ))}
          </div>
        ))}
      </VirtualizedGrid>
    </div>
  );
}

Caveats

  • The calculated size of the DynamicList is not "fully" dynamic. The component needs the user to supply a function that returns the size of each item based on the index. This is because calculating the height/width of each item automatically requires rendering them off-screen, which can be inefficient for large datasets.