FlatList onEndReached being called multiple times

Romit Kumar picture Romit Kumar · Nov 21, 2018 · Viewed 15.3k times · Source

I'm making a react native project where user can search images using Flickr API, Everything else is working fine but the problem i'm having while implementing pagination. I have used FlatList's onEndReached to detect when user has scrolled to the end on the list, but the problem is onEndReached is being called multiple times(including one during the first render). I have even disabled bounce as said here but it's still being called more than once

 export default class BrowserHome extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: false,
      tagParam: "cat",
      pageNum: -1,
      data: [],
      photosObj: ""
    };
  }

  componentDidMount() {
    this.setState({
      isLoading: true
    });
    try {
      this.makeRequest();
    } catch {
      console.log("error has occurred");
    }
  }

  makeRequest = () => {
    const { tagParam, pageNum } = this.state;
    let url = `https://api.flickr.com/services/rest/? 
               method=flickr.photos.search
               &api_key=${apiKey}&format=json&tags=${tagParam}
               &per_page=30&page=${pageNum + 1}&nojsoncallback=1`;
    fetch(url, {
      method: "GET"
    })
      .then(response => response.json())
      .then(responseJSON => {
        this.setState({
          data: this.state.data.concat(responseJSON.photos.photo),
          isLoading: false,
          pageNum: responseJSON.photos.page
        });
      })
      .catch(error => {
        console.log(error);
        this.setState({ isLoading: false });
        throw error;
      });
  };

  render() {
    if (this.state.isLoading) {
      return <ActivityIndicator animating={true} size="large" />;
    }

    return (
      <View
        style={{
          flex: 1,
          height: 200,
          justifyContent: "flex-start",
          width: screenSize.width,
          backgroundColor: "black"
        }}
      >
        <Text>This is browserhome</Text>
        <FlatList
          style={{
            width: screenSize.width
          }}
          numColumns={3}
          data={this.state.data}
          keyExtractor={item => item.id}
          bounces={false}
          onEndReachedThreshold={1}
          onEndReached={({ distanceFromEnd }) => {
            this.loadMoreItem();
            alert("end reached call");
          }}
          renderItem={({ item, index }) => (
            <>
              <ImageTile imageURL={this.createImageURL(item)} />
            //  <Text style={{ color: "white" }}>
             //   {index}
             //   {console.log(index)}
             // </Text>
            </>
          )}
        />
      </View>
    );
  }

  createImageURL(item) {
    let server = item.server,
      id = item.id,
      secret = item.secret;
    let urlString = `https://farm${
      item.farm
    }.staticflickr.com/${server}/${id}_${secret}_s.jpg`;
    return urlString;
  }

  loadMoreItem() {
    this.makeRequest();
  }
}

Answer

Shehzad Osama picture Shehzad Osama · Mar 13, 2020

This solution worked for me. Add onMomentumScrollBegin and modify onEndReached in FlatList Component.

<FlatList
style = { ...}
data = {data}
initialNumToRender = {10}
onEndReachedThreshold = {0.1}
onMomentumScrollBegin = {() => {this.onEndReachedCalledDuringMomentum = false;}}
onEndReached = {() => {
    if (!this.onEndReachedCalledDuringMomentum) {
      this.retrieveMore();    // LOAD MORE DATA
      this.onEndReachedCalledDuringMomentum = true;
    }
  }
}
/>