npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-api-pagination

v0.1.1

Published

A reusable HOC for rendering paginated FlatLists in React Native with infinite scroll, pull-to-refresh, and loading states.

Downloads

16

Readme

📱 React Native API Pagination

npm version License: MIT

A powerful and easy-to-use Higher-Order Component (HOC) for implementing paginated lists in React Native applications. You only need to provide two things: your item card component and your API function - everything else is handled automatically!

✨ Features

  • 🚀 Automatic Pagination: Handles infinite scrolling and API calls automatically
  • Loading States: Built-in loading indicators for initial load and load more
  • 🛡️ Error Handling: Comprehensive error handling with user-friendly messages
  • 🔄 Pull to Refresh: Native pull-to-refresh functionality
  • 📘 TypeScript Support: Full TypeScript support with proper type definitions
  • 🎨 Customizable: Pass custom props to your list items and configure FlatList behavior
  • Performance Optimized: Includes performance optimizations like removeClippedSubviews and windowSize

🎯 Why This Library?

Stop writing the same pagination code over and over again!

With this library, you only need to focus on:

  1. 🎨 How your item looks (your card component)
  2. 🔗 How to fetch your data (your API function)

Everything else is handled for you:

  • ✅ Pagination logic
  • ✅ Loading states (initial, load more, pull-to-refresh)
  • ✅ Error handling and display
  • ✅ Performance optimizations
  • ✅ Scroll-to-load-more functionality
  • ✅ Empty state handling

📦 Installation

npm install react-native-api-pagination

or

yarn add react-native-api-pagination

🚀 Quick Start

It's as simple as 1-2-3! You only need to provide two things, and the library handles all the pagination complexity.

🔗 Step 1: Create your API function

Just tell us how to fetch your data - we'll handle when and how often to call it!

// API function that returns paginated data
const getData = async (page) => {
  const response = await fetch(`https://api.example.com/items?page=${page}`);
  const data = await response.json();
  return data.items; // Should return an array of items
};

💡 That's it for the API! The library automatically:

  • Calls this function with page numbers (1, 2, 3, ...)
  • Handles loading states while the API is called
  • Manages errors if the API fails
  • Determines when to load more data

🧩 Step 2: Create your item card component

Just design how each item should look - we'll handle rendering the list!

import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

const ListItem = ({ item, index, onPress }) => {
  return (
    <TouchableOpacity style={styles.item} onPress={() => onPress(item)}>
      <Text style={styles.title}>{item.title}</Text>
      <Text style={styles.subtitle}>Item #{index + 1}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  item: {
    backgroundColor: '#f9f9f9',
    padding: 16,
    marginVertical: 4,
    borderRadius: 8,
  },
  title: {
    fontSize: 16,
    fontWeight: 'bold',
  },
  subtitle: {
    fontSize: 14,
    color: '#666',
    marginTop: 4,
  },
});

💡 That's it for the UI! The library automatically:

  • Renders your items in a FlatList
  • Handles scroll performance
  • Shows loading indicators
  • Manages empty states

🎯 Step 3: Combine them together

Connect your API and card component - we handle everything else!

import React from 'react';
import { SafeAreaView, Alert } from 'react-native';
import withPaginatedList from 'react-native-api-pagination';

// 🪄 Magic happens here - combine your API and card component
const PaginatedList = withPaginatedList(ListItem, getData);

const App = () => {
  const handlePress = (item) => {
    Alert.alert('Item Pressed', `You pressed: ${item.title}`);
  };

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <PaginatedList onPress={handlePress} />
    </SafeAreaView>
  );
};

export default App;

🎉 And you're done! Your paginated list now has:

  • ✅ Automatic pagination when scrolling to bottom
  • ✅ Pull-to-refresh functionality
  • ✅ Loading indicators
  • ✅ Error handling
  • ✅ Performance optimizations

🤯 What You Get For Free

By providing just 2 simple things (your card component + API function), this library automatically gives you:

| Feature | What it does | You had to code this manually before | | ----------------------- | ------------------------------------------- | ------------------------------------ | | 🔄 Auto Pagination | Loads next page when user scrolls to bottom | ✅ | | ⏳ Loading States | Shows spinners during API calls | ✅ | | 🔄 Pull to Refresh | Native pull-to-refresh gesture | ✅ | | 🚨 Error Handling | Shows error messages when API fails | ✅ | | 📱 Empty States | Shows message when no data available | ✅ | | ⚡ Performance | Optimized rendering for large lists | ✅ | | 🎯 State Management | Manages all pagination state internally | ✅ |

📋 Complete Working Example

Here's a complete example that you can copy-paste and run immediately:

💡 Notice how simple this is! We only define the card design and a dummy API function. All the pagination magic happens automatically.

import React from 'react';
import { Alert, Pressable, SafeAreaView, StyleSheet, Text } from 'react-native';
import withPaginatedList from 'react-native-api-pagination';

// 📊 Dummy data for demonstration (simulates your API response)
const dummyData = [
  // Page 1
  [
    { id: '1', title: 'Item 1' },
    { id: '2', title: 'Item 2' },
    { id: '3', title: 'Item 3' },
    { id: '4', title: 'Item 4' },
    { id: '5', title: 'Item 5' },
  ],
  // Page 2
  [
    { id: '6', title: 'Item 6' },
    { id: '7', title: 'Item 7' },
    { id: '8', title: 'Item 8' },
    { id: '9', title: 'Item 9' },
    { id: '10', title: 'Item 10' },
  ],
  // Page 3
  [
    { id: '11', title: 'Item 11' },
    { id: '12', title: 'Item 12' },
    { id: '13', title: 'Item 13' },
    { id: '14', title: 'Item 14' },
    { id: '15', title: 'Item 15' },
  ],
];

// 🔗 1️⃣ Your API function (the library calls this automatically)
const getData = async (page) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(dummyData[page - 1] || []);
    }, 1000); // Simulate network delay
  });
};

// 🎨 2️⃣ Your item card component (design how each item looks)
const Card = ({ item, handlePress }) => {
  return (
    <Pressable onPress={handlePress} style={styles.card}>
      <Text style={styles.cardText}>{item.title}</Text>
    </Pressable>
  );
};

// 🪄 3️⃣ Let the magic happen - combine them together
const PaginatedList = withPaginatedList(Card, getData);

// 🎉 4️⃣ Use your paginated list - that's it!
const App = () => {
  const handlePress = () => {
    Alert.alert('Card Pressed', 'You pressed a card!');
  };

  return (
    <SafeAreaView style={styles.container}>
      <PaginatedList handlePress={handlePress} />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    padding: 10,
  },
  card: {
    backgroundColor: '#f0f0f0',
    padding: 16,
    borderRadius: 8,
    marginBottom: 10,
  },
  cardText: {
    fontSize: 16,
    color: '#333',
  },
});

export default App;

🚀 What This Example Demonstrates

  • 📱 Initial Loading: Shows spinner while loading first page
  • ♾️ Infinite Scroll: Automatically loads page 2 when you scroll to bottom, then page 3, etc.
  • 🔄 Pull to Refresh: Pull down to refresh and reload from page 1
  • ⏳ Load More Indicator: Shows "Loading more..." at the bottom while loading next page
  • 📭 Empty State: Shows "No data available" if API returns empty array
  • 🚨 Error Handling: Shows error message if API fails

All of this with just 2 things from you: the Card component and getData function!

📚 API Reference

withPaginatedList(ListItemComponent, getData)

The magic function that turns your simple components into a powerful paginated list.

📥 Parameters

You only need to provide these 2 things:

  • ListItemComponent (Required) - Your custom item card component
    • What it receives: { item, index, ...yourCustomProps }
    • What you design: How each item should look and behave
    • Example: A card, a row, a tile - whatever fits your app's design
  • getData (Required) - Your API function that fetches data
    • Signature: (page: number) => Promise<Array>
    • What it does: Takes a page number (1, 2, 3...) and returns array of items
    • When it's called: Automatically by the library when needed
    • Example: const getData = (page) => fetch(\/api/items?page=${page}`)`

⚙️ Props

The returned component accepts these optional props:

  • flatListProps (Optional) - Customize the underlying FlatList behavior
  • horizontal (Optional) - Make the list scroll horizontally
  • ...customProps - Any props you want to pass to your ListItemComponent

💡 Everything else is handled automatically! Pagination logic, loading states, error handling, performance optimizations - all done for you.

🔧 Advanced Usage

🎛️ Custom FlatList Configuration

const App = () => {
  return (
    <SafeAreaView style={{ flex: 1 }}>
      <PaginatedList
        handlePress={handlePress}
        horizontal={false}
        flatListProps={{
          numColumns: 2,
          showsVerticalScrollIndicator: false,
          contentContainerStyle: { padding: 16 },
        }}
      />
    </SafeAreaView>
  );
};

🔷 With TypeScript

interface Item {
  id: string;
  title: string;
  description?: string;
}

interface CustomProps {
  onPress: (item: Item) => void;
  theme: 'light' | 'dark';
}

const ListItem: React.FC<{ item: Item; index: number } & CustomProps> = ({
  item,
  index,
  onPress,
  theme,
}) => {
  return (
    <TouchableOpacity onPress={() => onPress(item)}>
      <Text style={{ color: theme === 'dark' ? 'white' : 'black' }}>
        {item.title}
      </Text>
    </TouchableOpacity>
  );
};

const getData = async (page: number): Promise<Item[]> => {
  // Your API call here
  const response = await fetch(`/api/items?page=${page}`);
  return response.json();
};

const PaginatedList = withPaginatedList<Item, CustomProps>(ListItem, getData);

🚨 Error Handling

The component automatically handles errors and displays user-friendly messages. If your getData function throws an error, it will be caught and displayed to the user.

const getData = async (page) => {
  try {
    const response = await fetch(`/api/items?page=${page}`);
    if (!response.ok) {
      throw new Error('Failed to fetch data');
    }
    return await response.json();
  } catch (error) {
    throw new Error('Network error occurred');
  }
};

⏳ Loading States

The component provides three loading states:

  1. Initial Loading: Full-screen loading indicator when first loading data
  2. Load More: Footer loading indicator when loading additional pages
  3. Pull to Refresh: Native pull-to-refresh functionality

⚡ Performance Tips

The component includes several performance optimizations by default:

  • removeClippedSubviews={true}: Removes offscreen views to improve performance
  • maxToRenderPerBatch={10}: Limits the number of items rendered per batch
  • windowSize={10}: Controls the number of screens worth of items to render

You can override these settings via flatListProps:

<PaginatedList
  flatListProps={{
    maxToRenderPerBatch: 5,
    windowSize: 5,
    removeClippedSubviews: false,
  }}
/>

📋 Requirements

  • React Native >= 0.60
  • React >= 16.8 (for hooks support)

📄 License

MIT

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

💬 Support

If you encounter any issues or have questions, please open an issue on GitHub.