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,
/**
* 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
* treat it immutably.
* 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,
/**

View File

@ -60,6 +60,12 @@ type OptionalProps<SectionT: SectionBase<any>> = {
* Rendered in between each section.
*/
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
* 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,
/**
* 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
* treat it immutably.
* 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,
/**
@ -307,13 +307,16 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
}
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
// sure we're rendering a reasonable range here.
this.setState({
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)),
});
if (data !== this.props.data || extraData !== this.props.extraData) {
this._hasDataChangedSinceEndReached = true;
}
this._updateCellsToRenderBatcher.schedule();
}
@ -462,6 +465,7 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
}
_averageCellLength = 0;
_hasDataChangedSinceEndReached = true;
_hasWarned = {};
_highestMeasuredFrameIndex = 0;
_headerLength = 0;
@ -619,10 +623,12 @@ class VirtualizedList extends React.PureComponent<OptionalProps, Props, State> {
}
const distanceFromEnd = contentLength - visibleLength - offset;
const itemCount = getItemCount(data);
if (distanceFromEnd < onEndReachedThreshold * visibleLength &&
this._scrollMetrics.contentLength !== this._sentEndForContentLength &&
this.state.last === itemCount - 1) {
// Only call onEndReached for a given content length once.
if (this.state.last === itemCount - 1 &&
distanceFromEnd < onEndReachedThreshold * visibleLength &&
(this._hasDataChangedSinceEndReached ||
this._scrollMetrics.contentLength !== this._sentEndForContentLength)) {
// Only call onEndReached once for a given dataset + content length.
this._hasDataChangedSinceEndReached = false;
this._sentEndForContentLength = this._scrollMetrics.contentLength;
onEndReached({distanceFromEnd});
}