firebolt_ash
firebolt_ash

Reputation: 1324

React native List View onEndReached calling multiple times

I am facing some trouble using the List View onEndReached component in react native.

Render code:

@autobind
  _fetchMoreHistory(){

    console.log("Fetch more history called");

  }

<View style={[styles.Ctr]}>
   <ListView dataSource={this.state.txHistorySource}
         renderRow={ this._renderRow }
         onEndReached ={ this._fetchMoreHistory }
         onEndReachedThreshold  = {10}/>
</View>

The moment I open the screen _fetchMoreHistory is called twice and works normally after that onEndReached reached. Can someone help debug this ?

Upvotes: 6

Views: 9057

Answers (6)

BlaShadow
BlaShadow

Reputation: 11693

I've solved this problem by creating a state variable that tells me is the service is loading or not.

class Component1 extends Component {
public constructor(props) {
    super(props);

    this.state = {
        isLoading: false,
        listOfItems: []
    };
}

public componentDidMount() {
    this.loadData();
}

public render(){
    return (
        <FlatList
            data={this.state.listOfItems}
            renderItem={this.renderItem}
            onEndReachedThreshold={0.1}
            onEndReached={this.loadData}
        />
    );
}

private loadData = () => {
    if (this.state.isLoading === true) {
        /// Avoid make another request is there's happening a request right now
        return;
    }

    this.setState({isLoading: true});

    this.fetchData()
        .then(() => {
        /// Handle success response
            this.setState({isLoading: false});
        })
        .catch(() => {
              this.setState({isLoading: false});
        });
}

}

Upvotes: 2

pc31
pc31

Reputation: 1

You can write the code for fetching data in onMomentumScrollEnd rather than onEndReached, like this:

onMomentumScrollEnd={() => this.props.onEndReached()}

It might not be written as the available prop in the react native documentation, but if you will see the source code for FlatList, it uses Virtualized List which in return has the mentioned prop available.

Upvotes: 0

Pavel Poberezhnyi
Pavel Poberezhnyi

Reputation: 773

I had the same issue. But I figured out that I had the ScrollView that wraps my FlatList. When I removed it all started working properly.

It's a pity that NOTHING WAS SAID ABOUT THAT IN THE OFFICIAL DOCS

Upvotes: 6

Nicholas
Nicholas

Reputation: 3784

So my solution is simple. Don't use onEndReached at all. Use onScroll and detect the end of the scroll.

isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => { const paddingToBottom = 20; // how far from the bottom return layoutMeasurement.height + contentOffset.y >= contentSize.height - paddingToBottom; };

and the FlatList component

 <FlatList      
      data={data}        
       onScroll={({ nativeEvent }) => {
          if (this.isCloseToBottom(nativeEvent)) {
            // Dont forget to debounce or throttle this function.
            this.handleOnEndReached();
          }
       }}
  />

Upvotes: 4

tom nguyen
tom nguyen

Reputation: 316

You can try my solution

  1. You should configure limit > 10. Example limit = 15
  2. Add onMomentumScrollBegin prop to your ListView declaration.

    <ListView
      data={this.props.data}
      onEndReached={...}
      onEndReachedThreshold={0.5}
      ...
      onMomentumScrollBegin={() => { this.onEndReachedCalledDuringMomentum = false; }}
    />
    
  3. Modify your onEndReached callback to trigger data fetching only once per momentum.

    onEndReached =()=> { if(!this.onEndReachedCalledDuringMomentum) { this.props.fetchData(); this.onEndReachedCalledDuringMomentum = true; } };

Upvotes: 2

Ahmed Ali
Ahmed Ali

Reputation: 2668

I faced the same issue and searched a lot but didn't find any answers, so I used a condition to check if the first request got the data I fire onendreashed again else I don't

Example // onEndReached If(condition) { Make the call }

Upvotes: 5

Related Questions