Skip to content

Add useWindowedContainer hook #23

@owanturist

Description

@owanturist

The useWindowedContainer hook will create a host for multiple useWindowedList hooks working with the same container node. It will be helpful for windowing complex components such diff screens of git hosting tools.

The hook signature will look similar to this:

type UseWindowedContainer = <E extends HTMLElement>(options: {
  containerSize: number
  layout?: ListLayout
  initialScroll?: number
  containerOnScrollThrottleInterval?: number
  containerIsScrollingDebounceInterval?: number
}) => {
  isScrolling: boolean
  container: null | E
  setContainerRef(node: null | E): void
  scrollTo(px: number): void
  useWindowedListInContainer: UseWindowedListInContainer
}

And the UseWindowedListInContainer signature:

type UseWindowedListInContainer = (options: {
  itemSize: ItemSize
  itemCount: number
  overscanCount?: number
  firstItemStartAt?: number
  onItemsRendered?(renderedRange: ListRenderedRange): void
}) => {
  overscanFromIndex: number
  overscanBeforeIndex: number
  visibleFromIndex: number
  visibleBeforeIndex: number
  startSpace: number
  endSpace: number
  indexes: ReadonlyArray<number>
}

So this way everything related to a container will be handled in useWindowedContainer and the rest of the stuff related to list and items itself is per useWindowedListInContainer. This way it will define on scroll listeners only once per container node and exclude conflict of initialScroll properties.

const WindowedContainer = ({ itemsA, itemsB }) => {
  const { setContainerRef, useWindowedListInContainer } = useWindowedContainer({
    containerSize: 1000
  })

  const listA = useWindowedListInContainer({
    itemSize: 20,
    itemCount: itemsA.length
  })

  const listB = useWindowedListInContainer({
    firstItemStartAt: 20 * itemsA.length,
    itemSize: 50,
    itemCount: itemsB.length
  })

  return (
    <div className="scrollable-container" ref={setContainerRef}>
      <div>
        <div style={{ height: itemsA.startSpace }} />

        {listA
          .map(index => itemsA[index])
          .map(itemA => (
            <ItemAComponent key={itemA.id} item={itemA} />
          ))}

        <div style={{ height: itemsA.endSpace }} />
      </div>

      <div>
        <div style={{ height: itemsB.startSpace }} />

        {listB
          .map(index => itemsB[index])
          .map(itemB => (
            <ItemBComponent key={itemB.id} item={itemB} />
          ))}

        <div style={{ height: itemsB.endSpace }} />
      </div>
    </div>
  )
}

The basic useWindowedList hook will be a special case of useWindowedContainer with improved initialScroll and added scrollToItem.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions