Riverpod Adapter Examples
Complete working examples using the Fasq Riverpod adapter.
Basic User Management
Section titled “Basic User Management”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});}
// Providersfinal 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'), ), ), ], ), ); }}Pagination Example
Section titled “Pagination Example”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'), ), ], ), ], ), ); }}Optimistic Updates
Section titled “Optimistic Updates”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); }, ),);Next Steps
Section titled “Next Steps”- Riverpod Patterns - Architecture and best practices
queryProvider- Deep dive into data fetchingmutationProvider- Deep dive into updates