Last active
February 10, 2019 21:46
-
-
Save bdkent/56c1e6275a3a8bc5124af58e61703895 to your computer and use it in GitHub Desktop.
react-virtualized <AutoSizer> + <Masonry>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var DEFAULT_CELL_HEIGHT = 250; | |
var DEFAULT_CELL_SPACING = 10; | |
function createFullWidthMasonry(props) { | |
var cellSpacing = props.cellSpacing || DEFAULT_CELL_SPACING; | |
var cellHeight = props.cellHeight || DEFAULT_CELL_HEIGHT; | |
var keyMapper = props.keyMapper || _.identity(); | |
var elementRenderer = props.elementRenderer || _.constant(null); | |
function toDynamicCellWidth(width, columns) { | |
var spacing = (columns - 1) * cellSpacing; | |
return Math.floor((width - spacing) / columns); | |
} | |
return React.createClass({ | |
propTypes: { | |
elements: React.PropTypes.array.isRequired, | |
columns: React.PropTypes.number.isRequired | |
}, | |
getInitialState: function () { | |
return { | |
width: null | |
}; | |
}, | |
componentWillReceiveProps: function (nextProps) { | |
var self = this; | |
if (self.props.columns !== nextProps.columns || self.props.elements !== nextProps.elements) { | |
var width = self.state.width; | |
if (!_.isNil(width)) { | |
self._refreshCells(width, nextProps.columns); | |
} | |
} | |
}, | |
_setMasonryRef: function (ref) { | |
var self = this; | |
self._masonry = ref; | |
}, | |
_refreshCells: function (width, columns) { | |
var self = this; | |
var columnWidth = toDynamicCellWidth(width, columns); | |
self.setState({ | |
width: width | |
}); | |
if (_.isNil(self._cache)) { | |
self._cache = new CellMeasurerCache({ | |
defaultHeight: cellHeight, | |
defaultWidth: columnWidth, | |
fixedWidth: true | |
}); | |
self._cellPositioner = createMasonryCellPositioner({ | |
cellMeasurerCache: self._cache, | |
columnCount: columns, | |
columnWidth: columnWidth, | |
spacer: cellSpacing | |
}); | |
} else { | |
self._cache._defaultWidth = columnWidth; // HACKCITY | |
self._cache.clearAll(); | |
self._cellPositioner.reset({ | |
columnCount: columns, | |
columnWidth: columnWidth, | |
spacer: cellSpacing | |
}); | |
self._masonry.clearCellPositions(); | |
} | |
self.forceUpdate(); | |
}, | |
_onResize: function (props) { | |
var width = props.width; | |
var self = this; | |
self._refreshCells(width, self.props.columns); | |
}, | |
render: function () { | |
var self = this; | |
var elements = self.props.elements; | |
var cellCount = _.size(elements); | |
var renderCell = function (props) { | |
var index = props.index; | |
var key = props.key; | |
var style = props.style; | |
var parent = props.parent; | |
var element = elements[index]; | |
return ( | |
<CellMeasurer | |
cache={self._cache} | |
index={index} | |
key={key} | |
parent={parent} | |
> | |
<div style={style}>{elementRenderer(element)}</div> | |
</CellMeasurer> | |
); | |
}; | |
return ( | |
<AutoSizer onResize={self._onResize}> | |
{ | |
(function (props) { | |
var height = props.height; | |
var width = props.width; | |
if (_.isNil(self._cache)) { | |
return null; | |
} else { | |
return ( | |
<Masonry | |
ref={self._setMasonryRef} | |
keyMapper={keyMapper} | |
cellCount={cellCount} | |
cellMeasurerCache={self._cache} | |
cellPositioner={self._cellPositioner} | |
cellRenderer={renderCell} | |
height={height} | |
width={width} | |
/> | |
); | |
} | |
}) | |
} | |
</AutoSizer> | |
); | |
} | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks, this helped a lot! One critically important thing: using an anonymous (inline) function in AutoSizer is a must as if I use a named function (like 'renderMasonry') AutoSizer will cache it and not re-render it when props/state changes.
For me it was enough to do this in componentWillReceiveProp: