queryx_riverpod 0.1.1
queryx_riverpod: ^0.1.1 copied to clipboard
Riverpod bindings for QueryX — reactive queries, mutations, and infinite pagination with automatic widget rebuilds.
// A minimal Flutter app showing queryx_riverpod end to end. This file
// depends on flutter_riverpod (for ConsumerWidget/WidgetRef) even though
// the package itself only depends on the pure-Dart `riverpod` package —
// flutter_riverpod's WidgetRef is built directly on riverpod's Ref, so
// nothing here is queryx-specific glue.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:queryx_riverpod/queryx_riverpod.dart';
Future<void> main() async {
final queryClient = QueryClient(
defaultStaleTime: const Duration(minutes: 1),
logger: QueryxLogger(enabled: true),
);
runApp(
ProviderScope(
overrides: [queryxClientProvider.overrideWithValue(queryClient)],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: UsersScreen());
}
}
// --- fake backend --------------------------------------------------------
class FakeApi {
static int _likes = 41;
static Future<List<String>> getUsers() async {
await Future<void>.delayed(const Duration(milliseconds: 400));
return ['Ada Lovelace', 'Linus Torvalds', 'Grace Hopper'];
}
static Future<int> likeLastUser() async {
await Future<void>.delayed(const Duration(milliseconds: 300));
_likes += 1;
return _likes;
}
}
// --- providers -------------------------------------------------------------
final usersProvider = queryProvider<List<String>>(
QueryKey(['users']),
(ref) => FakeApi.getUsers,
);
final likesKey = QueryKey(['lastUser', 'likes']);
final likesProvider = queryProvider<int>(
likesKey,
(ref) => () async => 41,
);
final likeUserProvider = mutationProvider<int, void, int>(
(ref) => (_) => FakeApi.likeLastUser(),
optionsBuilder: (ref) {
final client = ref.read(queryxClientProvider);
return MutationOptions<int, void, int>(
onMutate: (_) async {
final snapshot = client.getQueryData<int>(likesKey) ?? 0;
client.updateQueryData<int>(likesKey, (n) => (n ?? 0) + 1);
return snapshot;
},
onSuccess: (serverCount, _, __) {
client.setQueryData<int>(likesKey, serverCount);
},
onError: (error, _, snapshot) {
if (snapshot != null) client.setQueryData<int>(likesKey, snapshot);
},
);
},
);
// --- UI --------------------------------------------------------------------
class UsersScreen extends ConsumerWidget {
const UsersScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final users = ref.watch(usersProvider);
final likes = ref.watch(likesProvider);
final likeMutation = ref.watch(likeUserProvider);
return Scaffold(
appBar: AppBar(title: const Text('queryx_riverpod example')),
body: RefreshIndicator(
onRefresh: () => ref.read(usersProvider.notifier).refresh(),
child: users.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (e) => Center(child: Text('Error: ${e.message}')),
data: (people) => ListView(
children: [
for (final person in people) ListTile(title: Text(person)),
ListTile(
title: Text('Likes: ${likes.data ?? '—'}'),
trailing: likeMutation.isLoading
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: IconButton(
icon: const Icon(Icons.favorite_border),
onPressed: () =>
ref.read(likeUserProvider.notifier).mutate(null),
),
),
],
),
),
),
);
}
}