bvaughn / react-window

React components for efficiently rendering large lists and tabular data
https://react-window.now.sh/
MIT License
15.91k stars 787 forks source link

Adding flexible height to a FixedSizeList #587

Closed andrewtremblay closed 3 years ago

andrewtremblay commented 3 years ago

I often have to use a list in a full page format, but the requirement that the height needs to be provided as a number for vertical lists is slightly inconvenient.

Here's my current workaround, which allows me to consider the FixedSizeList as if it had a flexGrow of 1 by calculating the height with a dummy div:

export default function DynamicHeightFixedSizeList(
  props: Partial<FixedSizeListProps>
) {
  const listWrapperRef = useRef<HTMLDivElement | null>(null);
  const dimensions = useMemo(
    () => ({
      top: listWrapperRef.current?.offsetTop || 0,
      height: listWrapperRef.current?.offsetHeight || 0,
      left: listWrapperRef.current?.offsetLeft || 0,
      width: listWrapperRef.current?.offsetWidth || 0,
    }),
    [
      listWrapperRef.current,
      listWrapperRef.current?.offsetTop,
      listWrapperRef.current?.offsetHeight,
      listWrapperRef.current?.offsetLeft,
      listWrapperRef.current?.offsetWidth,
    ]
  );
  return (
    <>
      <div
        ref={listWrapperRef}
        style={{
          display: 'flex',
          flexDirection: 'column',
          flexGrow: 1,
        }}
      >
        &nbsp;
      </div>
      {listWrapperRef.current && (
        <div
          style={{
            position: 'fixed',
            top: dimensions.top,
            height: dimensions.height,
            left: dimensions.left,
            width: dimensions.width,
          }}
        >
          <FixedSizeList {...(props as any)} height={dimensions.height} />
        </div>
      )}
    </>
  );
}

My questions are: Does anyone have any similar approaches to this that might be better? Is there a reason why such a thing cannot be included out of the box?

andrewtremblay commented 3 years ago

Nevermind! I found out about AutoSizer, that seems to be the most common solution to this; https://github.com/bvaughn/react-window#can-a-list-or-a-grid-fill-100-the-width-or-height-of-a-page

I should have read the docs more closely.

This is what my component looks like now.

import { FixedSizeList, FixedSizeListProps } from 'react-window';
import AutoSizer, { Size } from 'react-virtualized-auto-sizer';

/** technically has both dynamic height and width */
export default function DynamicHeightFixedSizeList(
  props: Partial<FixedSizeListProps>
) {
  return (
    <div style={{ display: 'flex', flexGrow: 1 }}>
      <AutoSizer>
        {({ height, width }: Size) => (
          <FixedSizeList {...(props as any)} height={height} width={width} />
        )}
      </AutoSizer>
    </div>
  );
}