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
Maintainers
Readme
📱 React Native API Pagination
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
removeClippedSubviewsandwindowSize
🎯 Why This Library?
Stop writing the same pagination code over and over again!
With this library, you only need to focus on:
- 🎨 How your item looks (your card component)
- 🔗 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-paginationor
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
- What it receives:
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}`)`
- Signature:
⚙️ Props
The returned component accepts these optional props:
flatListProps(Optional) - Customize the underlying FlatList behaviorhorizontal(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:
- Initial Loading: Full-screen loading indicator when first loading data
- Load More: Footer loading indicator when loading additional pages
- 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 performancemaxToRenderPerBatch={10}: Limits the number of items rendered per batchwindowSize={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.
