Skip to content

Version 2 changes #302

@bvaughn

Description

@bvaughn

This is an umbrella issue to share my plans for the upcoming version 2.0 release of react-window.

Feedback is appreciated and will be taken into consideration. I ask that you be understanding if I'm not able to accommodate all requests. I'll try to do my best to weigh feature requests against bundle size, runtime performance, and maintenance concerns.

I expect that upgrading from version 1 to 2 may require substantial code changes, many of which will not be possible to automate with code mods. Because of this, particularly for application code, I would advise against upgrading existing code unless you have a strong reason (e.g. you need support for dynamic size content).

I am also going to go ahead and pin the current docs to the domain react-window-v1.now.sh so they will not be lost when I update for version 2.


Table of contents:
  • Support fewer components
  • Use render props API
  • No more horizontal lists support
  • Only grids support RTL
  • Changes to onScroll callback timing
  • Other changes/deprecations

Fewer components

One way to help manage complexity is to reduce the number of components the library supports. I am currently planning on supporting only the following component types in version 2:

  • SimpleList (previously FixedSizeList)
    • This highly optimized list component should be used when row heights are fixed (and known ahead of time).
  • List (previously DynamicSizeList)
    • This list should be used for dynamically sized content (e.g. chat, newsfeed). It requires the ResizeObserver API (or polyfill).
  • Grid (previously VariableSizeGrid)
    • This component should be used for tabular data (e.g. spreadsheets) that should be virtualized along both vertical and horizontal axis. It supports variable size rows and columns, but does not support automatically measuring and updating their sizes.

Render props

One of the major changes from react-virtualized to react-window was the decision to treat children as React elements (e.g. React.createElement(children, props))) rather than as render props (e.g. children(props)).

There were a couple of motivations for doing this:

  • React provides built-in solutions for memoization (e.g. React.memo, useMemo, shouldComponentUpdate) so I didn't need to implement my own caching abstraction for item renderers.
  • APIs like hooks and suspense "just work" inside of item renderers.
  • Keys can be managed by react-window without requiring the render prop to pass them along (and without requiring cloneElement calls).

Unfortunately there were also some downsides:

  • Inline item renderers incur a high cost. Because their "type" (the function definition) gets recreated each time the parent component renders, React deeply unmounts and remounts their rendered tree. This means that docs need to teach people not to use them even though they're often more convenient.
  • Because inline functions couldn't be used to close over local scope, it was more complicated for item renderers to share state with parents, requiring APIs like itemData and a custom areEqual comparison export.

After taking the above pros and cons into consideration, I've decided to convert to a render props approach for react-window as well. This means that complicated examples like this can be re-written more easily:

const Example = ({ height, items, toggleItemActive, width }) => (
  <List
    height={height}
    itemCount={items.length}
    itemRenderer={({ index, key, style }) => {
      const item = items[index];
      return (
        <div key={key} onClick={() => toggleItemActive(index)} style={style}>
          {item.label} is {item.isActive ? "active" : "inactive"}
        </div>
      );
    }}
    itemSize={35}
    width={width}
  />
);

No more horizontal list support

Previously, list components supported both horizontal and vertical layout modes. In order to simplify implementation and maintenance, and because the overwhelmingly common use case is vertical lists, I will be removing support for layout="horizontal".


RTL support

Grid components will continue to support direction="RTL", but lists will not (since they will only support a vertical layout). This tradeoff is being made to enable lists to be smaller and easier to maintain.


onItemsRendered and onScroll callback changes

List and grid components currently support onItemsRendered and onScroll callback props. These callbacks are called during the commit phase (after the list or grid has completed rendering). This can be useful in that it is always safe to perform a side effect (like analytics logging) in response to these callbacks, but it has a downside as well: any scroll synchronized updates must be done in a second ("cascading") render.

Version 2 will make a change to the onScroll callback to address this. The onScroll callback will be called during the event's dispatch cycle so that any update will be batched (by React) with the list or grid's own update.

The onItemsRendered callback will be replaced with a onItemsDisplayed prop, although it will continue to be called during the commit cycle. This change is being made to enable the list component to more aggressively optimize render performance by pre-rendering at idle priority and make use of experimental APIs like display locking.


Other props changes/deprecations

There are several pending deprecations (with DEV warnings) which will be removed:

  • innerTagName and outerTagName for all list and grid components. (Use innerElementType and outerElementType instead.)
  • overscanCount, overscanColumnsCount, and overscanRowsCount for grid component. (Use overscanColumnCount and overscanRowCount instead.)
  • overscanCount will be removed for list components, in favor of a dynamic overscanning approach.
  • "horizontal" and "vertical" values for direction. (These were moved to layout, but they will be removed entirely in version 2.)
  • The itemData prop (and the corresponding data prop passed to item renderers) will be removed because the change to a render prop API no longer make this necessary.
  • The useIsScrolling prop (and the corresponding isScrolling prop passed to item renderers) will be removed because the changes to pre-rendering and display locking would make this more expensive to implement.
  • Scroll align parameters will change slightly. The previously named "auto" will now be named "minimal". The new default value will be "smart" (rather than "auto").

Note that some of the above deprecated props may not still be relevant given the other planned changes, but I'm listing them here anyway for completeness sake.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions