Skip to content

Riverpod Adapter Examples

Complete working examples using the Fasq Riverpod adapter.

A complete example showing user listing, creation, and deletion:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fasq_riverpod/fasq_riverpod.dart';
class User {
final String id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
}
// Providers
final usersProvider = queryProvider<List<User>>(
'users'.toQueryKey(),
() => api.fetchUsers(),
);
final createUserProvider = mutationProvider<User, Map<String, String>>(
(data) => api.createUser(data),
options: MutationOptions(
onSuccess: (user, variables) {
// Invalidate users query to refetch
ref.invalidate(usersProvider);
},
),
);
final deleteUserProvider = mutationProvider<void, String>(
(id) => api.deleteUser(id),
options: MutationOptions(
onSuccess: (_, id) {
ref.invalidate(usersProvider);
},
),
);
class UserManagementScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final usersAsync = ref.watch(usersProvider);
final createUserState = ref.watch(createUserProvider);
final deleteUserState = ref.watch(deleteUserProvider);
return Scaffold(
appBar: AppBar(title: Text('User Management')),
body: Column(
children: [
Expanded(
child: usersAsync.when(
loading: () => Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Error: $error'),
ElevatedButton(
onPressed: () => ref.read(usersProvider.notifier).refetch(),
child: Text('Retry'),
),
],
),
),
data: (users) => ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: deleteUserState.isLoading
? null
: () => ref.read(deleteUserProvider.notifier).mutate(user.id),
),
);
},
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: createUserState.isLoading
? null
: () => _showCreateUserDialog(context),
child: createUserState.isLoading
? CircularProgressIndicator()
: Text('Add User'),
),
),
],
),
);
}
}

Implementing pagination with function-wrapped providers:

final paginatedUsersProvider = (int page) => queryProvider<List<User>>(
['users', 'page', page].toQueryKey(),
() => api.fetchUsersPage(page: page, limit: 10),
);
class PaginatedUsersScreen extends ConsumerStatefulWidget {
@override
ConsumerState<PaginatedUsersScreen> createState() => _PaginatedUsersScreenState();
}
class _PaginatedUsersScreenState extends ConsumerState<PaginatedUsersScreen> {
int _currentPage = 1;
@override
Widget build(BuildContext context) {
final usersAsync = ref.watch(paginatedUsersProvider(_currentPage));
return Scaffold(
appBar: AppBar(title: Text('Paginated Users')),
body: Column(
children: [
Expanded(
child: usersAsync.when(
loading: () => Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')),
data: (users) => ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _currentPage > 1 ? () {
setState(() => _currentPage--);
} : null,
child: Text('Previous'),
),
Text('Page $_currentPage'),
ElevatedButton(
onPressed: () {
setState(() => _currentPage++);
},
child: Text('Next'),
),
],
),
],
),
);
}
}

Implementing optimistic updates for instant feedback:

final updateUserProvider = (String userId) => mutationProvider<User, String>(
(newName) => api.updateUser(userId, newName),
options: MutationOptions(
onMutate: (newName) {
// Optimistically update the list cache manually via the client
final client = ref.read(fasqClientProvider);
final currentUsers = client.getQueryData<List<User>>('users'.toQueryKey());
if (currentUsers != null) {
final optimistic = currentUsers.map((u) =>
u.id == userId ? User(id: u.id, name: newName, email: u.email) : u
).toList();
client.setQueryData('users'.toQueryKey(), optimistic);
}
},
onSuccess: (user, newName) {
// Invalidate to ensure sync with server
ref.invalidate(usersProvider);
},
onError: (error, newName) {
// Rollback on error
ref.invalidate(usersProvider);
},
),
);