How to implement infinite Scroll effect in React Native with Laravel API

Published: 1 year ago - Updated: 1 year ago

8 minutes - 215 Words

article 'How to implement infinite Scroll effect in React Native with Laravel API' banner

Summary

In this tutorial, we will learn how to implement infinite scroll in React Native using Flatlist and Laravel API as our backend.

Introduction

Infinite Scrolling is a feature that allows you to load more data when the user scrolls to the bottom of the list. It is a great way to add more content to your app without having to make additional API calls.

Benefit of this technique is that we don’t all of our data at once , we only get our data when the user needs it this will allow our app to have faster load time which is very essential for our App.

In this tutorial I have assumed that you have already installed the React Native CLI or Expo and have installed and set up Laravel and its dependencies. You have a table in your database which has the data of your app and you have a Route which is responsible for fetching the data from the database.

Let’s Get Started

Laravel Backend

Let’s start with our API. As you see I have a table called article which has some articles stored in it. Bellow is the route that is responsible for fetching the data from the database.

Route::get("/get-articles",[ArticlesController::class,'getArticlesApi']);

Now we have our API route which is responsible for fetching the data. In our ArticlesController.php we have a method called getArticlesApi which is as bellow.

<?php

namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;

class ArticlesController extends Controller
{
	...
	...

	public function getArticlesApi()
    {
        $articles = Article::orderBy('created_at', 'DESC')
														->with("website:id,title")
														->paginate(6);

        return response()->json(['status' => 1, 'articles' => $articles]);
    }

	...
	...
}

To Explain the above code.

  • The orderBy('created_at', 'DESC') is used to sort the data in descending order to get the latest articles first.
  • The with("website:id,title") is used to get the website title of the article from a separate table using eager loading which is a feature of Eloquent.
  • The **paginate(6**) is used to get the data in chunks of 6.

The paginate(6) is very important because we are using the infinite scrolling feature and we don’t want to load all the data at once. The paginate method will provide us with the data in chunks of 6 and also links to get the rest of our data when we scroll to the bottom of the list.

Now we have our API route which is responsible for fetching the data. In our ArticlesController.php we have a method called getArticlesApi() to get the data.

If you have done everything correctly then you should see the data in the response. The data will be something like this:

{
  "status": 1,
  "articles": {
    "current_page": 1,
    "data": [
      {
        "id": 150,
        "title": "First Mover Asia: Bitcoin Falls in Pre-Holiday Trading;",
        "excerpt": "A recovery in the Tether-Chinese yuan pairing",
        "image": "",
        "category_id": 1,
        "website_id": 2,
        "created_at": "2021-11-25T04:05:16.000000Z",
        "updated_at": "2021-11-25T04:06:00.000000Z",
        "slug": "first-mover-asia-bitcoin-falls-in-pre-holiday-trading-ether-drops",
        "website": { "id": 2, "title": "Yahoo Finance" }
      },
      {
        "id": 151,
        "title": "US regulators aim for greater legal ",
        "excerpt": "US banking regulators have shared their .",
        "image": "",
        "category_id": 1,
        "website_id": 2,
        "created_at": "2021-11-25T04:05:16.000000Z",
        "updated_at": "2021-11-25T04:05:16.000000Z",
        "slug": "us-regulators-aim-for-greater-legal-",
        "website": { "id": 2, "title": "Yahoo Finance" }
      },
     .....
    ],
    "first_page_url": "https://localhost:8000/api/get-articles?page=1",
    "from": 1,
    "last_page": 20,
    "last_page_url": "https://localhost:8000/api/get-articles?page=20",
    "links": [
      { "url": null, "label": "« Previous", "active": false },
      {
        "url": "https://localhost:8000/api/get-articles?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": "https://localhost:8000/api/get-articles?page=2",
        "label": "2",
        "active": false
      }
    ],
    "next_page_url": "https://localhost:8000/api/get-articles?page=2",
    "path": "https://localhost:8000/api/get-articles",
    "per_page": 6,
    "prev_page_url": null,
    "to": 6,
    "total": 119
  }
}

To analyze the response,

  • We can use the response.data property to access the data.
  • The Important thing that we need here is next_page_url using this link we can get the next page of data and we will get the same response with 6 new articles in the response and if the data is remaining then we will get a new next_page_url.

Since our backend is fully functional and we have the data we can now start to build the frontend and move to React Native.

Frontend React Native

For React Native, I have assumed the you have a working project and installed all the dependencies including axios which is used to make the API calls.

In our React Native we will have function to get data from the API which will be something like this:

const [news, setNews] = useState(null);
const [nextPageUrl, setNextPageUrl] = useState(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
	getData();
}, []);

const getData = () => {
	API.get("https://localhost:8000/api/get-articles")
	.then((res) => {
			setNews(res.data.articles.data);
			setNextPageUrl(res.data.articles.next_page_url);
			if (isLoading) setIsLoading(false);
	}).catch((err) => {
			// console.log(err.message);
			setErrMsg(err.message);
			if (isLoading) setIsLoading(false);
	});
};

When we get the data in then() we will set the state of news and nextPageUrl.

The news is our 6 articles which we got from the API and the nextPageUrl is the link to the next page of data.

The isLoading is a Boolean which we will use to show the loading spinner.

To display the data we will use the FlatList component which is a list of items.

I won’t bore you with the details of how to use the FlatList component. Since if your are looking for infinite scrolling, you can use the FlatList component.

The part of the Flatlist that we are interested in is the onEndReached and onEndReachedThreshold property of the Flatlist.

onEndReached gets a function which will be called when the user scrolls to the end of the list or scroll past the onEndReachedThreshold property.

onEndReachedThreshold is a number between 0 and 1 which is the fraction of the list that has been scrolled before onEndReached is called.

...

	return (
		<FlatList
			onEndReached={getNextPageData}
			onEndReachedThreshold={0.5}
			...

		>

	);

...

The onEndReached will call the getNextPageData() function when the user scrolls to the end of the list.

The getNextPageData function will be something like this:

const [loadingMore, setLoadingMore] = useState(false);

	const getNextPageData = () => {
		// we check if the nextPageUrl state is not null
		if (nextPageUrl != null) {
			// is a flag to show or hide the loading spinner at the bottom of the list
			setLoadingMore(true);
			axios.get(nextPageUrl)
				.then((res) => {
				setNews([...news, ...res.data.articles.data]);
				setNextPageUrl(res.data.articles.next_page_url);
				// we use the if(loadingMore) to avoid unnecessary setting of the state.
				// this will assure that we only change state when it necessary
				if(loadingMore) setLoadingMore(false);
				})
				.catch((err) => {
				setLoadingMore(false);
				setErrMsg(err);
				});
		} else {
			setErrMsg("No more data");
		}
  	};

The getNextPageData function will call the axios.get function to get the next page of data.
but first we check that the existing nextPageUrl is not null because if is it null then we don’t have any other data to get and we wont call the API.

If our request is successful we will get 6 new articles and a new nextPageUrl from the API which we need store in the state.

Since we don’t want to lose our previous data we will use the spread operator like bellow:

setNews([...news, ...res.data.articles.data]);

To add the new data to the existing data. The new data will be appended at the bottom of the list which is what we want.

We will also set the loadingMore flag to false to hide the loading spinner. and finally we set the nextPageUrl to the new value which we got from the API.

in here if there is no more data left in the database the nextPageUrl will be null, this is helping because at the beginning of this function we checked for the nextPageUrl to not be null.

To summarize what we have done in React Native is:

  • Get the data from the API
  • Get the next_page_url and store it in a State Variable
  • Define the getNextPageData function
  • Set onEndReached and onEndReachedThreshold for the FlatList
import React ,{useState,useEffect} from "react";
import {
  ActivityIndicator,
  FlatList,
  Image,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from "react-native";
import SkeletonContent from "react-native-skeleton-content";
import axios from "axios";

const News = ({ isDarkTheme }) => {
	const [news, setNews] = useState(null);
	const [nextPageUrl, setNextPageUrl] = useState(null);
	const [loadingMore, setLoadingMore] = useState(false);
	const [errMsg, setErrMsg] = useState("");
	const [isLoading, setIsLoading] = useState(true);

	useEffect(() => {
		// 1- Get the data from the API
			getData();
  	}, []);

	const getData = () => {
		API.get("https://localhost:8000/api/get-articles")
		.then((res) => {
			setNews(res.data.articles.data);
			// 2- Get the next_page_url and store it in a State Variable
				setNextPageUrl(res.data.articles.next_page_url);
			if (refreshing) setRefreshing(false);
			if (isLoading) setIsLoading(false);
		})
		.catch((err) => {
			// console.log(err.message);
			setErrMsg(err.message);
			if (refreshing) setRefreshing(false);
			if (isLoading) setIsLoading(false);
		});
  	};

	// 4- define the getNextPageData function
	const getNextPageData = () => {
		// we check if the nextPageUrl state is not null
		if (nextPageUrl != null) {
			// is a flag to show or hide the loading spinner at the bottom of the list
			setLoadingMore(true);
			axios.get(nextPageUrl)
				.then((res) => {
				setNews([...news, ...res.data.articles.data]);
				setNextPageUrl(res.data.articles.next_page_url);
				// we use the if(loadingMore) to avoid unnecessary setting of the state.
				// this will assure that we only change state when it necessary
				if(loadingMore) setLoadingMore(false);
				})
				.catch((err) => {
				setLoadingMore(false);
				setErrMsg(err);
				});
		} else {
			setErrMsg("No more data");
		}
  	};

	
	if(isLoading) {
	return (
		...
	)
	}

	
	// 3- set onEndReached and onEndReachedThreshold for the FlatList
	return (
    <FlatList
	  
      onEndReached={getNextPageData}
      onEndReachedThreshold={0.5}
      data={news}
      keyExtractor={(item) => `${item.id}`}
      renderItem={({ item }) => {
        return (
          ...
        );
      }}
    />
  );
	
}

That was all about infinite scrolling in React Native and Laravel to get you started with the topic. Obviously you can use the same code in React Native or React JS. You can do a lot more with the data taken from the API and implement it in your project or add new features to it.

I hope this has helped you to understand how to use the API in your project. thanks for reading. Don’t forget to share this article with your friends.

See it in actions:

Add Comment

Conversations (0)

Sign up for our newsletter

Stay up to date with the latest news and articles.