likes
comments
collection
share

react-window虚拟渲染(不固定高度)

作者站长头像
站长
· 阅读数 91

前言

最近有个需求,需要渲染大量的列表,列表项的高度还不确定,之前用过react-virtualized,可以解决不固定高度的问题,但这个库有点大,比较重。react-window官方没有提供该案例。

react-window实现

react-window提供了两种组件VariableSizeList可变size,FixedSizeList固定size两种类型的组件。我们借助VariableSizeList来实现不固定高度。我们先看看VariableSizeList的简单使用方法。需重点关注一下resetAfterIndex(index, false);改方法,因为react-window内容部为了性能做了缓存,我们调用改方法可以清楚缓存,重新计算结果。

VariableSizeList 详解

List 组件

主要使用VariableSizeList组件, props上有一个itemSize属性,改属性接收一个方法,参数为index, 具体内容可见getItemSize。组件内部提供了一个setItemSize方法,供Item组件设置高度。

const Example = () => {
    const [sizes, setSizes] = useState({ 1: 50 }); // 根据索引记录列表的高度
    const [count, setCount] = useState(100); // 列表数量
  
    const listRef = useRef();
    console.log("sizes", sizes);
  
    useEffect(() => {
      return () => {
        console.log("父组件");
      };
    }, []);
    // 根据索引获取Item的尺寸
    const getItemSize = useCallback(
      (index) => {
        return sizes[index] || 150;
      },
      [sizes]
    );
  
    // 根据索引,设置Item高度
    const setItemSize = useCallback((index = 1, size = 10) => {
      console.log("setItemSize", index, size);
      setSizes((prevSize) => {
        return {
          ...prevSize,
          [index]: size
        };
      });
      // setCount(count + 1);
      // 根据索引,重置缓存位置。
      listRef.current.resetAfterIndex(index, false);
    }, []);
    
    const rowRender = useCallback(({ index: rowIndex, style }) => {
      return (
        <div index={rowIndex} style={style}>
          <Row
            // style={style}
            index={rowIndex}
            key={rowIndex}
            setItemSize={setItemSize}
            rowIndex={rowIndex}
          />
        </div>
      );
    }, []);
  
    return (
      <>
        {
          <List
            className="List"
            height={400}
            itemCount={count}
            itemSize={getItemSize}
            width={300}
            ref={listRef}
          >
            {rowRender}
          </List>
        }
      </>
    );
  };

RowItem组件

RowItem组件在页面第一次渲染完成后,获取组件的高度,调用一下父组件setItemSize 方法,更新下高度。

/**
 * 项(Item)组件
 */
const Row = ({ index, style, setItemSize }) => {
  const itemRef = useRef();
  useEffect(() => {
    const elementHeight = itemRef.current.offsetHeight;
    console.log("elementHeight", elementHeight);
    setItemSize(index, elementHeight);
    return () => {
      console.log("卸载1");
    };
  }, []);
  return (
    <div
      ref={itemRef}
      className={index % 2 ? "ListItemOdd" : "ListItemEven"}
      style={style}
    >
      Row {index}
    </div>
  );
};


完整的代码可以查看 codesandbox.io/s/modern-vi…

结束语

大家有不固定高度的虚拟渲染需求,可以用React-window尝试一下。

如果你觉得该文章不错,不妨

1、点赞,让更多的人也能看到这篇内容

2、关注我,让我们成为长期关系

3、关注公众号「前端有话说」,里面已有多篇原创文章,和开发工具,欢迎各位的关注,第一时间阅读我的文章

转载自:https://juejin.cn/post/7120463085856358414
评论
请登录