riverpod_infinite_query 0.1.0
riverpod_infinite_query: ^0.1.0 copied to clipboard
Lightweight infinite query utilities for Riverpod and Flutter. Compose paged FutureProviders while keeping Riverpod cache, refresh, and invalidation behavior.
riverpod_infinite_query #
Lightweight infinite query utilities for riverpod-based Flutter apps.
Design #
This package is built upon FutureProvider of riverpod and without complex implementation.
It only coordinates multiple FutureProvider.family pages so they behave like one infinite query.
- One request payload maps to one page
FutureProvider - One infinite query is a list of page providers working together
- Adding a new page only requests the new page
- Cache, refresh, invalidation, and
autoDisposestill come from Riverpod
InfiniteQueryResponse<T> is just the collected result of each page response T.
request [1] | page 1 |
request [1, 2] | page 2 |
| page 1 |
request [1, 2, 3] | page 3 |
| page 2 |
| page 1 |
append one more page -> fetch only the new FutureProvider
refresh/invalidate -> keep Riverpod behavior
Installation #
dependencies:
riverpod_infinite_query: ^<latest_version>
CLI
flutter pub add riverpod_infinite_query
Example #
final postsPageProvider = FutureProvider.autoDispose.family<PostPage, int>((ref, page) {
return api.fetchPage(page);
});
final postsProvider = createInfiniteQueryProvider<PostPage, int>(postsPageProvider);
class PostsScreen extends HookConsumerWidget {
const PostsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final controller = useScrollController();
final result = useInfiniteScroll<PostPage, int>(
ref: ref,
provider: postsProvider,
initial: 1,
controller: controller,
next: (lastPage, currentPage) {
if (lastPage != null && !lastPage.hasMore) {
return null;
}
return currentPage + 1;
},
);
final pages = result.data.value?.data ?? const <PostPage>[];
final items = [
for (final page in pages) ...page.items,
];
return RefreshIndicator(
onRefresh: () => result.refresh((_) => [1]),
child: ListView.builder(
controller: controller,
itemCount: items.length + (result.data.isLoading ? 1 : 0),
itemBuilder: (context, index) {
if (index == items.length) {
return const Padding(
padding: EdgeInsets.all(16),
child: Center(child: CircularProgressIndicator()),
);
}
return ListTile(title: Text(items[index].title));
},
),
);
}
}
See example/ for a complete runnable Flutter app.