Pagination and Pull to refresh in Flatlist with custom hooks
Tags: reactnative, javascript
Published: 2024-02-06 21:00:55


To implement a pagination hook and pull-to-refresh functionality based on your provided data structure, you can follow these steps:

## Pagination Hook and Pull-to-Refresh Implementation

**1. Setup Initial State and Imports:**
Start by importing necessary dependencies and setting up initial state variables.


Get API scheme like this:

```
{
  data: [],
  totalResult: 0,
  status: true,
  pageNo: 1,
  totalPages: 1,
  perPage: 10,
};
```
else modify this `const result = await response.json();` in below to look like above format.

`usePagination.jsx`
```
import React, { useState, useEffect, useCallback } from 'react';

const initialData = {
  data: [],
  totalResult: 0,
  status: true,
  pageNo: 1,
  totalPages: 1,
};

const usePagination = () => {
  const [initialLoader, setInitialLoader] = useState(true);
  const [data, setData] = useState(initialData.data);
  const [totalResult, setTotalResult] = useState(initialData.totalResult);
  const [pageNo, setPageNo] = useState(initialData.pageNo);
  const [totalPages, setTotalPages] = useState(initialData.totalPages);
  const [refreshing, setRefreshing] = useState(false);
  const [loadingMore, setLoadingMore] = useState(false);

  // Function to fetch data for a given page number
  const fetchData = async (page, perPage = 10) => {
    try {
      // Simulate fetching data from API
      // Replace this with your actual API call
      const response = await fetch(`https://dummyjson.com/products?limit=${perPage}&skip=${page}`);
      const resultOld = await response.json();
      const result = {
        data: resultOld?.products,
        totalResult: resultOld?.total,
        status: true,
        pageNo: page,
        totalPages: Math.ceil(resultOld?.total / perPage) || 10,
      };

      if (result.status) {
        if (page === 1) {
          setData(result.data);
        } else {
          setData([...data, ...result.data]);
        }
        setTotalResult(result.totalResult);
        setPageNo(result.pageNo);
        setTotalPages(result.totalPages);
      } else {
        console.error('Failed to fetch data');
      }
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      setRefreshing(false);
      setLoadingMore(false);
      setInitialLoader(false);
    }
  };

  // Initial data fetch on component mount
  useEffect(() => {
    fetchData(pageNo);
  }, []);

  // Function to handle pull-to-refresh
  const handleRefresh = useCallback(() => {
    setRefreshing(true);
    fetchData(1); // Refreshes the first page
  }, []);

  // Function to handle load more (pagination)
  const loadMore = () => {
    if (!loadingMore) {
      if (pageNo < totalPages) {
        setLoadingMore(true);
        const nextPage = pageNo + 1;
        fetchData(nextPage);
      }
    }
  };

  return {
    data,
    totalResult,
    refreshing,
    loadingMore,
    handleRefresh,
    loadMore,
    initialLoader,
  };
};

export default usePagination;

```


**USAGE:**

```
const FeedsListScreen = ({ navigation }) => {
  const {
    styles,
    theme: { colors },
  } = useStyles(stylesheet);
  const { data, totalResult, refreshing, loadingMore, handleRefresh, loadMore, initialLoader } =
    usePagination();

  const renderFooter = () => {
    if (!loadingMore || data.length < 8) return null; // Do not show footer loader for the first page
    return <ActivityIndicator animating size="large" />;
  };

  return initialLoader ? (
    <CustomLoader />
  ) : (
    <FlatList
      data={data}
      renderItem={({item,index})=><View/>}
      keyExtractor={(item) => item._id}
      refreshControl={
        <RefreshControl
          refreshing={refreshing}
          onRefresh={handleRefresh}
        />
      }
      renderFooter={renderFooter}
      onEndReached={loadMore}
      onEndReachedThreshold={0.1}
    />
  );
};

export default FeedsListScreen;

```