How to make an API call when end of the page reached in React and Re-render components – using API Pagination


Ahamed Fazil Buhari
Senior Developer
Published On :   20 Dec 2018
Visit Count
Today :  5    Total :   259


Hello everyone,

In this article we will see how to call an event from React compoenent when we reach end of the page. This functionality is useful when we have to make API calls based on pageIndex and pageSize. For example, if there are millions of data return by your API and you don’t want to show all the result in one single API call instead if you make call by pageIndex, pageSize (if your API permits) then when end of the page is scrolled, we can make API call to the server which return few more data and so on. Well, there many custom components available in github and this approach is more like FlatList in React Native.

Let’s say I have component called SearchResult and this will make API call and returns the result. The result will be loaded into other component which will loop through all the items, once the user reach end of the page then it will automatically make an API call with increased pageIndex and pageSize, because my API accepts pagination and payload. Main thing we need to notice here is how we handle event trigger when user reaches end of the page.

Well I am using typescript and office ui fabric for design, so my component looks more like below

 interface ISearchResultProps {
   searchInfo: any;
 }
 
 interface ISearchResultState {
   resultAll: any;
   isFetched: boolean;
   isError: boolean;
   isLoadingMore: boolean;
   loadMoreError: any;
   isEnd: boolean;
   error: any;
 }
 
 export default class SearchResult extends React.Component<
   ISearchResultProps,
   ISearchResultState
 > {
   constructor(props: ISearchResultProps) {
     super(props);
     this.state = {
       resultAll: {},
       isFetched: false,
       isError: false,
       isLoadingMore: false,
       isEnd: false,
       loadMoreError: "",
       error: ""
     };
     this.handleScroll = this.handleScroll.bind(this);
   }
 
   public async componentDidMount() {
     // EventListener for scroll
     window.addEventListener("scroll", this.handleScroll);
     // First API call
     let resultAll: any = await getResultsFromAPI(this.props.searchInfo);
     if (resultAll) {
       this.setState({
         resultAll: resultAll,
         isFetched: true
       });
     } else {
       this.setState({
         isFetched: true,
         isError: true
       });
     }
   }
 
   // this function will be called when user scrolling
   private handleScroll() {
     // condition to check, End of the page reached?
     if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
       const resultAll = this.state.resultAll;
       let searchQ = this.props.searchInfo;
       // Condition to avoid multiple API call when user reach end of Page before previous call is over
       if (resultAll.Common && !this.state.isLoadingMore && !this.state.isEnd) {
         this.setState(
           {
             isLoadingMore: true
           },
           async () => {
             try {
               searchQ.pageIndex = searchQ.pageSize;
               searchQ.pageSize = searchQ.pageSize + 20;
               searchQ.PollURL = resultAll.Common.PollURL;
               const newResult: any = await getResultsFromAPI(searchQ);
               if (newResult && newResult.Results.length > 0) {
                 // pushing values to existing state by using immutable-helper
                 // https://www.npmjs.com/package/immutability-helper
                 const immutableResult = update(this.state.resultAll, {
                   Results: { $push: newResult.Results }
                 });
                 this.setState({
                   resultAll: immutableResult,
                   isLoadingMore: false
                 });
               } else {
                 this.setState({
                   isEnd: true
                 });
               }
             } catch {
               this.setState({
                 loadMoreError: "Error while getting more data from the server.",
                 isLoadingMore: false
               });
             }
           }
         );
       }
     }
   }
 
   public render(): JSX.Element {
     return (
       <div>
         {!this.state.isFetched ? (
           <Spinner
             className="spinner-style"
             size={SpinnerSize.large}
             label="Getting, result..."
           />
         ) : this.state.isError ? (
           <MessageBar
             title={`Error while getting data from server. - ${
               this.state.error
             }`}
           />
         ) : this.state.resultAll.Results ? (
           this.state.resultAll.Results.map((result: any, key: number) => {
             return (
               <div key={key}>
                 <Results resultInfo={result} />
               </div>
             );
           })
         ) : (
           <MessageBar title="Something went wrong" />
         )}
         {this.state.resultAll && this.state.resultAll.length <= 0 && (
           <MessageBar title="No result found." />
         )}
         {this.state.loadMoreError && (
           <MessageBar title="Something went wrong" />
         )}
         {this.state.isLoadingMore && !this.state.isEnd && (
           <Spinner size={SpinnerSize.large} label="Loading, more results..." />
         )}
         {this.state.isEnd && <MessageBar title="End of search result" />}
       </div>
     );
   }
 }
 
 


Happy Coding

Ahamed

Categories