I recently used react-virtualized
List
to display rows of fixed-height, variable-width image cards and it worked great.
My List
rowRenderer
uses an array of rows of image card elements. That is, an array of arrays of react components, as JSX.
See my final function, cardsRows
, for how I build the rows based on element widths and screen width.
Here's how it looks:

Hope this helps!
Some snippets of my code:
import {AutoSizer, List} from 'react-virtualized';
...
updateDimensions() {
this.setState({
screenWidth: window.innerWidth,
});
}
componentDidMount() {
window.addEventListener("resize", this.updateDimensions);
}
componentDidUpdate(prevProps, prevState) {
const props = this.props;
const state = this.state;
if (JSON.stringify(props.imageDocs) !== JSON.stringify(prevProps.imageDocs) || state.screenWidth !== prevState.screenWidth)
this.setState({
cardsRows: cardsRows(props, state.screenWidth),
});
}
rowRenderer({key, index, style, isScrolling}) {
if (!this.state.cardsRows.length)
return '';
return (
<div id={index} title={this.state.cardsRows[index].length} key={key} style={style}>
{this.state.cardsRows[index]}
</div>
);
}
...
render() {
return (
<div style={styles.subMain}>
<AutoSizer>
{({height, width}) => (<List height={height}
rowCount={this.state.cardsRows.length}
rowHeight={164}
rowRenderer={this.rowRenderer}
width={width}
overscanRowCount={2}
/>
)}
</AutoSizer>
</div>
);
}
...
const cardsRows = (props, screenWidth) => {
const rows = [];
let rowCards = [];
let rowWidth = 0;
const distanceBetweenCards = 15;
for (const imageDoc of props.imageDocs) {
const imageWidth = getWidth(imageDoc);
if (rowWidth + distanceBetweenCards * 2 + imageWidth <= screenWidth) {
rowCards.push(cardElement(imageDoc));
rowWidth += distanceBetweenCards + imageWidth;
}
else {
rows.push(rowCards);
rowCards = [];
rowWidth = distanceBetweenCards;
}
}
if (rowCards.length) {
rows.push(rowCards);
}
return rows;
};
const styles = {
subMain: {
position: 'absolute',
display: 'block',
top: 0,
right: 0,
left: 0,
bottom: 0,
}
};