@bestyled/contrib-flatlist

Implementation of FlatList for the BeStyled Design System

Usage no npm install needed!

<script type="module">
  import bestyledContribFlatlist from 'https://cdn.skypack.dev/@bestyled/contrib-flatlist';
</script>

README

bestyled/flatlist

A performant, infinite, virtualized list for React. See react-virtualized, react-window and react-tiny-virtual-list for prior art; this package is designed to

  • Be extremely fast, with fine grained use of React Hooks (16.8+) instead of the less granular PureComponent used by existing solutions
  • Delegate absolution positioning to the browser with use of FlexBox layout (removes need for top / size styles on every element, as we simply observe what the browser does and then size the outer container accordingly)
  • Assumes variable size vertical items by default, with auto-resizing whenever the layout changes; if you want a FixedSizeList or Grid you may want to stick with react-window
  • Avoid dependencies on CellMeasurer and other techniques to pre-determine height of every item and instead build right in using a very simple react hook for ResizeObserver (polyfilled using react-resize-observer)
  • Support scrolling to Index without calculating the size of all intermediate entries, particularly useful for Scroll-To-End based conversational user interfaces
  • Removes advanced APIs like sticky index and sticks to the absolute minimum required to run a variable dynamic list

Unlike just about all other implemetations of virtualized lists for React, no old-school React Components inside, with just one code file for the Functional Component and one file for the Size and Position state manager.

Example Usage

import React from 'react'
import { render } from 'react-dom'
import { FlatList } from '@bestyled/contrib-flatlist'
import { AutoSizer } from '@bestyled/contrib-common'

// kick off the smoothscroll polyfill (for Safari, etc.)
import smoothscroll from 'smoothscroll-polyfill'
smoothscroll.polyfill()

const listItems = items.map((item, index) => (
  <React.Fragment key={index}>
    <RowHeader date={item.header} />
    <RowCard item={item} />
  </React.Fragment>
))

const renderRow = ({ index }) => {
  return listItems[index]
}

render(
  <AutoSizer flex={1} my={3}>
    {({ height }) => (
      <List
        estimatedItemSize={100}
        height={height}
        itemCount={listItems.length}
        scrollToIndex={listItems.length - 1}
        scrollToAlignment="end"
        renderItem={renderRow}
      />
    )}
  </AutoSizer>
)

Prop Types

Property Type Required? Description
height Number | String* Height of List. This property will determine the number of rendered items.
itemCount Number The number of items you want to render
renderItem Function Responsible for rendering an item given it's index: ({index: number}): React.PropTypes.node. The returned element must handle the given item key; any styling is up to you.
scrollToIndex Number Item index to scroll to (by forcefully scrolling if necessary) x
scrollToAlignment String Used in combination with scrollToIndex, this prop controls the alignment of the scrolled to item. One of: 'start', 'center', 'end' or 'auto'. Use 'start' to always align items to the top of the container and 'end' to align them bottom. Use 'center' to align them in the middle of the container. 'auto' scrolls the least amount possible to ensure that the specified scrollToIndex item is fully visible.
stickyIndices Number[] An array of indexes (eg. [0, 10, 25, 30]) to make certain items in the list sticky (position: sticky)
overscanCount Number Number of extra buffer items to render above/below the visible items. Tweaking this can help reduce scroll flickering on certain browsers/devices.
estimatedItemSize Number Used to estimate the total size of the list before all of its items have actually been measured. The estimated total height is progressively adjusted as items are rendered.
onScroll Function Callback invoked whenever the scroll offset changes within the inner scrollable region. It has the following signature: (scrollTop: number, event: React.UIEvent<HTMLDivElement>).

Dependencies

Three standalone React Hooks are used from @bestyled/contrib-common. These could easily be incorporated yourself to eliminate this dependency. One of these has an additional depdency on ResizeObserver polyfill

  • useResizeObserver - simple wrapper around ResizeObserver to be notified whenever an element size has been changed
  • useForceUpdate - convenience method to force a state change
  • useInstanceRef - convenience method to lazy initialize an instance reference

Peer dependency on smoothscroll-polyfill and react

License

Apache 2.0