onEndReached should clear when data changes

Summary: it's possible to update data and not have the content length change, which could prevent onEndReached from ever firing again, so fix that.

Reviewed By: bvaughn, yungsters

Differential Revision: D4783818

fbshipit-source-id: ec4640f4b8cf820165b045eaafee6fb41c0b0499
This commit is contained in:
Spencer Ahrens 2017-03-28 19:59:20 -07:00 committed by Facebook Github Bot
parent 5643bbc11d
commit 22a4205bdd
3 changed files with 21 additions and 9 deletions

View File

@ -63,8 +63,8 @@ type OptionalProps<ItemT> = {
columnWrapperStyle?: StyleObj, columnWrapperStyle?: StyleObj,
/** /**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If * A marker property for telling the list to re-render (since it implements `PureComponent`). If
* your `renderItem` function depends on anything outside of the `data` prop, stick it here and * any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the
* treat it immutably. * `data` prop, stick it here and treat it immutably.
*/ */
extraData?: any, extraData?: any,
/** /**

View File

@ -60,6 +60,12 @@ type OptionalProps<SectionT: SectionBase<any>> = {
* Rendered in between each section. * Rendered in between each section.
*/ */
SectionSeparatorComponent?: ?ReactClass<any>, SectionSeparatorComponent?: ?ReactClass<any>,
/**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If
* any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the
* `data` prop, stick it here and treat it immutably.
*/
extraData?: any,
/** /**
* How many items to render in the initial batch. This should be enough to fill the screen but not * How many items to render in the initial batch. This should be enough to fill the screen but not
* much more. Note these items will never be unmounted as part of the windowed rendering in order * much more. Note these items will never be unmounted as part of the windowed rendering in order

View File

@ -51,8 +51,8 @@ type OptionalProps = {
disableVirtualization: boolean, disableVirtualization: boolean,
/** /**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If * A marker property for telling the list to re-render (since it implements `PureComponent`). If
* your `renderItem` function depends on anything outside of the `data` prop, stick it here and * any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the
* treat it immutably. * `data` prop, stick it here and treat it immutably.
*/ */
extraData?: any, extraData?: any,
/** /**
@ -307,13 +307,16 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
} }
componentWillReceiveProps(newProps: Props) { componentWillReceiveProps(newProps: Props) {
const {data, getItemCount, maxToRenderPerBatch} = newProps; const {data, extraData, getItemCount, maxToRenderPerBatch} = newProps;
// first and last could be stale (e.g. if a new, shorter items props is passed in), so we make // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make
// sure we're rendering a reasonable range here. // sure we're rendering a reasonable range here.
this.setState({ this.setState({
first: Math.max(0, Math.min(this.state.first, getItemCount(data) - 1 - maxToRenderPerBatch)), first: Math.max(0, Math.min(this.state.first, getItemCount(data) - 1 - maxToRenderPerBatch)),
last: Math.max(0, Math.min(this.state.last, getItemCount(data) - 1)), last: Math.max(0, Math.min(this.state.last, getItemCount(data) - 1)),
}); });
if (data !== this.props.data || extraData !== this.props.extraData) {
this._hasDataChangedSinceEndReached = true;
}
this._updateCellsToRenderBatcher.schedule(); this._updateCellsToRenderBatcher.schedule();
} }
@ -462,6 +465,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
} }
_averageCellLength = 0; _averageCellLength = 0;
_hasDataChangedSinceEndReached = true;
_hasWarned = {}; _hasWarned = {};
_highestMeasuredFrameIndex = 0; _highestMeasuredFrameIndex = 0;
_headerLength = 0; _headerLength = 0;
@ -619,10 +623,12 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
} }
const distanceFromEnd = contentLength - visibleLength - offset; const distanceFromEnd = contentLength - visibleLength - offset;
const itemCount = getItemCount(data); const itemCount = getItemCount(data);
if (distanceFromEnd < onEndReachedThreshold * visibleLength && if (this.state.last === itemCount - 1 &&
this._scrollMetrics.contentLength !== this._sentEndForContentLength && distanceFromEnd < onEndReachedThreshold * visibleLength &&
this.state.last === itemCount - 1) { (this._hasDataChangedSinceEndReached ||
// Only call onEndReached for a given content length once. this._scrollMetrics.contentLength !== this._sentEndForContentLength)) {
// Only call onEndReached once for a given dataset + content length.
this._hasDataChangedSinceEndReached = false;
this._sentEndForContentLength = this._scrollMetrics.contentLength; this._sentEndForContentLength = this._scrollMetrics.contentLength;
onEndReached({distanceFromEnd}); onEndReached({distanceFromEnd});
} }