【问题标题】:How do I tell the Masonry component that its cells have changed their height?我如何告诉 Masonry 组件它的单元格已经改变了它们的高度?
【发布时间】:2017-11-15 09:36:33
【问题描述】:

我有一个反应组件,它以网格模式显示一维项目列表。每个项目都具有相同的宽度和高度,并且它们位于三列内。这些可能有很多,所以我决定让 react-virtualized 旋转一下,使用 Masonry 组件,它似乎是为这个用例而编写的。它运作良好,但有一点需要注意:如果物品的高度发生变化,我无法让 Masonry 注意到。

这是一个简化的例子:

constructor(props) {
    [...]
    this.cellMeasurerCache = new CellMeasurerCache({
        defaultHeight: this.state.height,
        fixedWidth: true,
    });

    this.cellPositioner = createMasonryCellPositioner({
        cellMeasurerCache: this.cellMeasurerCache,
        columnCount: 3,
        columnWidth: 250,
        spacer: 20,
    });
}

[...]

cellRenderer({ index, key, parent, style }) {
    return (
        <CellMeasurer
            cache={this.cellMeasurerCache}
            index={index}
            key={key}
            parent={parent}
        >
            <div style={style}>
                [...]
            </div>
        </CellMeasurer>
    );
}

resetMasonry() {
    this.cellMeasurerCache.clearAll();

    this.cellPositioner.reset({
        cache: this.cellMeasurerCache,
        columnCount: 3,
        columnWidth: 250,
        spacer: 20,
    });

    this.masonryRef.recomputeCellPositions();
}

render() {
    return (
        <AutoSizer>
            {({ height, width }) =>
                <Masonry
                    cellCount={this.state.list.length}
                    cellMeasurerCache={this.cellMeasurerCache}
                    cellPositioner={this.cellPositioner}
                    cellRenderer={this.cellRenderer}
                    height={height}
                    ref={this.setMasonryRef}
                    width={width}
                />
            }
        </AutoSizer>
    );
}

resetMasonry 在组件的高度状态发生变化时被调用。我已经从几个 stackoverflow 答案和其他资源中提取了当前代码,甚至查看了源代码,但没有任何效果。我注意到我没有告诉 cellMeasurerCache 或其他任何关于高度变化的信息,所以我真的不应该指望它能够工作,但似乎没有办法在那里获取这些信息,即使是通过实例化一个新的CellMeasurerCache

顺便说一句,如果我在cellPositioner.reset 中更改columnWidth,Masonry 组件也会相应更新,果然如此。

有人知道我缺少什么来让它为高度变化工作吗?谢谢!

【问题讨论】:

    标签: react-virtualized


    【解决方案1】:

    如果您的Masonry 单元格的大小发生变化,您需要清除CellMeasurerCache 中的缓存大小,然后确保cellPositioner 也知道新的大小。例如:

    // Clear cached measurements since sizes have changed:
    cellMeasurerCache.clearAll()
    
    // Let your component know it needs to re-render
    this.setState({...}, () => {
      // Assuming you're using the default createCellPositioner()
      // Let it know of any values that may have changed:
      cellPositioner.reset({
        columnCount,
        columnWidth,
        spacer
      })
    
      // Tell Masonry to discard any cached position data:
      masonryRef.clearCellPositions()
    })
    

    您可以通过更改列宽在RV site 上看到Masonry 组件的演示,该组件更改列高。该演示的源代码也可以在in the GitHub repo 获得。

    根据您的描述,我不建议使用Masonry。我实际上只是建议以与我在此示例中的方式类似的方式使用Listhttp://plnkr.co/edit/zjCwNeRZ7XtmFp1PDBsc?p=preview

    关键位是根据可用宽度动态计算每行的项目数,然后给List一个调整后的rowCount

      const itemsPerRow = Math.floor(width / ITEM_SIZE);
      const rowCount = Math.ceil(ITEMS_COUNT / itemsPerRow);
    

    【讨论】:

    • 非常感谢您的回答!使用List 被证明是正确的选择(我已经知道如何使用它,因为我在另一个显示一长串全角项目的组件中这样做了)。我的用例中的列数永远不会改变,因此很容易适应。现在我想知道Masonry 组件的用例是什么,如果不是这个?此外,事实证明我缺少的是使用clearCellPositions 而不是recomputeCellPositions。这样做会导致组件注意到高度的变化,但它只更新了它的一些项目,而不是所有项目......
    • 无论如何,使用简单的List 效果很好,再次感谢!
    • Masonry 用于 Pinterest 布局。事实上,在与 Pinterest 的一位工程师讨论后,我专门为 Pinterest 构建了该组件。 (不确定他们是否选择使用它。)由于您的物品的高度都相同,List 更易于使用。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 2015-05-26
    • 1970-01-01
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多