问题
I have a react component that displays a one-dimensional list of items in a grid pattern. Every item has the same width and height, and they are located within three columns. There can be a lot of these, so I decided to give react-virtualized a whirl, using the Masonry component, which seems to have been written for precisely this use case. It works well, but for one caveat: If the items change their height, I cannot get Masonry to notice.
Here's a reduced example:
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
is called when the component's height state has changed. I have cargo-culted the current code from several stackoverflow answers and other resources, even went over the source code, but nothing works. I've noticed that I'm not telling the cellMeasurerCache or anything else about the height change, so I really shouldn't expecting it to work, but there seems to be no way to get that information in there, not even by instantiating a new CellMeasurerCache
.
Incidentally, if I change the columnWidth within cellPositioner.reset
, the Masonry component updates accordingly, sure enough.
Does anybody know what I'm missing to get it working for a height change? Thanks!
回答1:
If your Masonry
cell's sizes change, you need to clear the cached sizes in your CellMeasurerCache
and then make sure the cellPositioner
is aware of the new sizes also. For example:
// 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()
})
You can see a demo of a Masonry
component with changing column heights on the RV site just by changing the column width. The source code for that demo is available in the GitHub repo also.
From what you're describing though, I wouldn't suggest using Masonry
. I would actually just suggest using a List
in a similar way to how I did in this example: http://plnkr.co/edit/zjCwNeRZ7XtmFp1PDBsc?p=preview
The key bit is to calculate the number of items per row dynamically based on the available width, and then you give List
an adjusted rowCount
:
const itemsPerRow = Math.floor(width / ITEM_SIZE);
const rowCount = Math.ceil(ITEMS_COUNT / itemsPerRow);
来源:https://stackoverflow.com/questions/44524350/how-do-i-tell-the-masonry-component-that-its-cells-have-changed-their-height