diff --git a/Examples/UIExplorer/js/FlatListExample.js b/Examples/UIExplorer/js/FlatListExample.js index 825da7f7c..a85504d28 100644 --- a/Examples/UIExplorer/js/FlatListExample.js +++ b/Examples/UIExplorer/js/FlatListExample.js @@ -52,6 +52,7 @@ class FlatListExample extends React.PureComponent { state = { data: genItemData(1000), + debug: false, horizontal: false, filterText: '', fixedHeight: true, @@ -90,6 +91,7 @@ class FlatListExample extends React.PureComponent { {renderSmallSwitchOption(this, 'horizontal')} {renderSmallSwitchOption(this, 'fixedHeight')} {renderSmallSwitchOption(this, 'logViewable')} + {renderSmallSwitchOption(this, 'debug')} alert('onRefresh: nothing to refresh :P')} - refreshing={false} onViewableItemsChanged={this._onViewableItemsChanged} ref={this._captureRef} + refreshing={false} shouldItemUpdate={this._shouldItemUpdate} /> diff --git a/Libraries/Experimental/VirtualizedList.js b/Libraries/Experimental/VirtualizedList.js index f821f8d77..660fe730f 100644 --- a/Libraries/Experimental/VirtualizedList.js +++ b/Libraries/Experimental/VirtualizedList.js @@ -74,6 +74,11 @@ type OptionalProps = { FooterComponent?: ?ReactClass<*>, HeaderComponent?: ?ReactClass<*>, SeparatorComponent?: ?ReactClass<*>, + /** + * `debug` will turn on extra logging and visual overlays to aid with debugging both usage and + * implementation. + */ + debug?: ?boolean, /** * DEPRECATED: Virtualization provides significant performance and memory optimizations, but fully * unmounts react instances that are outside of the render window. You should only need to disable @@ -272,6 +277,7 @@ class VirtualizedList extends React.PureComponent { item={item} key={key} onLayout={this._onCellLayout} + onUnmount={this._onCellUnmount} parentProps={this.props} /> ); @@ -345,7 +351,11 @@ class VirtualizedList extends React.PureComponent { }, cells, ); - return ret; + if (this.props.debug) { + return {ret}{this._renderDebugOverlay()}; + } else { + return ret; + } } componentDidUpdate() { @@ -375,7 +385,7 @@ class VirtualizedList extends React.PureComponent { _onCellLayout = (e, cellKey, index) => { const layout = e.nativeEvent.layout; - const next = {offset: this._selectOffset(layout), length: this._selectLength(layout), index}; + const next = {offset: this._selectOffset(layout), length: this._selectLength(layout), index, inLayout: true}; const curr = this._frames[cellKey]; if (!curr || next.offset !== curr.offset || @@ -391,6 +401,13 @@ class VirtualizedList extends React.PureComponent { } }; + _onCellUnmount = (cellKey: string) => { + const curr = this._frames[cellKey]; + if (curr) { + this._frames[cellKey] = {...curr, inLayout: false}; + } + }; + _onLayout = (e: Object) => { this._scrollMetrics.visibleLength = this._selectLength(e.nativeEvent.layout); this.props.onLayout && this.props.onLayout(e); @@ -405,6 +422,53 @@ class VirtualizedList extends React.PureComponent { this._headerLength = this._selectLength(e.nativeEvent.layout); }; + _renderDebugOverlay() { + const normalize = this._scrollMetrics.visibleLength / this._scrollMetrics.contentLength; + const framesInLayout = []; + const itemCount = this.props.getItemCount(this.props.data); + for (let ii = 0; ii < itemCount; ii++) { + const frame = this._getFrameMetricsApprox(ii); + if (frame.inLayout) { + framesInLayout.push(frame); + } + } + const windowTop = this._getFrameMetricsApprox(this.state.first).offset; + const frameLast = this._getFrameMetricsApprox(this.state.last); + const windowLen = frameLast.offset + frameLast.length - windowTop; + const visTop = this._scrollMetrics.offset; + const visLen = this._scrollMetrics.visibleLength; + const baseStyle = {position: 'absolute', top: 0, right: 0}; + return ( + + {framesInLayout.map((f, ii) => + + )} + + + + ); + } + _selectLength(metrics: {height: number, width: number}): number { return !this.props.horizontal ? metrics.height : metrics.width; } @@ -572,6 +636,7 @@ class CellRenderer extends React.Component { index: number, item: Item, onLayout: (event: Object, cellKey: string, index: number) => void, + onUnmount: (cellKey: string) => void, parentProps: { ItemComponent: ItemComponentType, getItemLayout?: ?Function, @@ -584,6 +649,9 @@ class CellRenderer extends React.Component { _onLayout = (e) => { this.props.onLayout(e, this.props.cellKey, this.props.index); } + componentWillUnmount() { + this.props.onUnmount(this.props.cellKey); + } shouldComponentUpdate(nextProps, nextState) { const curr = {item: this.props.item, index: this.props.index}; const next = {item: nextProps.item, index: nextProps.index}; @@ -593,7 +661,7 @@ class CellRenderer extends React.Component { const {item, index, parentProps} = this.props; const {ItemComponent, getItemLayout} = parentProps; const element = ; - if (getItemLayout) { + if (getItemLayout && !parentProps.debug) { return element; } return (