【问题标题】:Async loading of components in react-virtualized?在反应虚拟化中异步加载组件?
【发布时间】:2019-01-05 10:04:08
【问题描述】:

我在一个组件中实现了一个反应虚拟化的砌体网格,如下所示:

const MasonrySubmissionRender = (media: InputProps) => {

    function cellRenderer({ index, key, parent, style }: MasonryCellProps) {
        //const size = (media.submissionsWithSizes && media.submissionsWithSizes.length > index) ? media.submissionsWithSizes[index].size : undefined
        //const height = size ? (columnWidth * (size.height / size.width)) : defaultHeight;
        function getCard(index: number, extraProps: any) {
            var Comp = media.cardElement ? media.cardElement : SubmissionCard

            return <Comp submission={media.media[index]} {...media.customCardProps} />
        }


        return (
            <div>
                <CellMeasurer
                    cache={cache}
                    index={index}
                    key={key}
                    parent={parent}>
                    <div style={style}>
                        {getCard(index, media.customCardProps)}
                    </div>
                </CellMeasurer>
            </div>
        );
    }

    return (
        <Masonry
            overscanByPixels={1000}
            autoHeight={false}
            cellCount={media.media.length}
            cellMeasurerCache={cache}
            cellPositioner={cellPositioner}
            cellRenderer={cellRenderer}
            style={{ backgroundColor: 'red' }}
            height={900}
            width={900}
        />
    );
};

它呈现一个相当复杂的组件列表,其中包含一系列芯片、css 动画等。

由于这种渲染速度非常慢,即使使用 react-virtualized。

我想实现一个像 imgur.com 这样的系统,其中组件本身不需要立即加载,只显示一个剪影,而我可以让组件准备在后台渲染。

我知道有一种方法可以在滚动时换出组件,但他隐藏了所有组件,包括已经渲染的组件。

【问题讨论】:

    标签: reactjs typescript react-virtualized


    【解决方案1】:

    像所有 react-virtualized 单元格/行渲染器一样,masonry's cell render 传递了一个 isScrolling 属性。当砌体滚动时,您可以渲染占位符而不是单元格内容:

    if (isScrolling) return ( 
      <div>placeholder</div>
    );
    

    此外,每当重新渲染无状态组件时,您都会重新创建所有函数。这会给垃圾收集器带来额外的开销,并且还可能导致组件不必要地重新渲染。

    将组件转换为类组件。 cellRenderer 应该是一个实例方法(使用类属性或在构造函数中绑定)。 getCard可以是类方法,也可以从组件中提取出来,调用函数时传递media

    您的代码应该是这样的(未经测试):

    function getCard(media: InputProps, index: number) {
      var Comp = media.cardElement ? media.cardElement : SubmissionCard
    
      return <Comp submission = {
          media.media[index]
        } { ...media.customCardProps }
      />
    }
    
    class MasonrySubmissionRender extends React.Component {
    
      cellRenderer = ({
        index,
        key,
        parent,
        style,
        isScrolling
      }: MasonryCellProps) => {
        if (isScrolling) return ( 
          <div>placeholder</div>
        );
    
        return (
          <div>
              <CellMeasurer
                  cache={cache}
                  index={index}
                  key={key}
                  parent={parent}>
                  <div style={style}>
                      {getCard(media, index)}
                  </div>
              </CellMeasurer>
          </div>
        );
      }
    
      render() {   
        return (
          <Masonry
            overscanByPixels={1000}
            autoHeight={false}
            cellCount={media.media.length}
            cellMeasurerCache={cache}
            cellPositioner={cellPositioner}
            cellRenderer={this.cellRenderer}
            style={{ backgroundColor: 'red' }}
            height={900}
            width={900}
          />
        );
      }
    }
    

    【讨论】:

    • 经过进一步调查,我发现我的代码或 react-virtualized 中存在一个错误,导致砌体内部的组件立即全部加载,从而消除了 react-virtualized 的优点。我在 react-virtualized git 上发布了我的发现。话虽如此,您的评论对于让我了解如何编写高性能代码非常有帮助。我确实有一个问题要跟进 'isScrolling' 解决方案,有没有办法知道哪些组件已经渲染,以便我知道不要将树桩组件放在它的位置?
    • react-virtualized 将删除不在视图中或其缓冲区中的组件,因此通常不需要知道渲染了什么。但是,只要项目在视图中,您可能希望显示它们而不是占位符。您可以将“isScrolling”传递给组件,每个组件都可以保持其“渲染”状态,并决定使用标志来渲染它的内容或占位符。
    猜你喜欢
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    • 2019-03-09
    • 2017-07-27
    • 2011-12-29
    • 2018-09-14
    • 2018-06-21
    • 2021-09-03
    相关资源
    最近更新 更多