queryProvider
The queryProvider is a Riverpod provider factory that creates and manages Fasq queries. It returns AsyncValue<T>, Riverpod’s native async type, for seamless integration with reactive UI patterns.
Basic Usage
Section titled “Basic Usage”import 'package:flutter_riverpod/flutter_riverpod.dart';import 'package:fasq_riverpod/fasq_riverpod.dart';
// Define your query providerfinal usersProvider = queryProvider<List<User>>( 'users'.toQueryKey(), () => api.fetchUsers(),);
class UsersScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final usersAsync = ref.watch(usersProvider);
return Scaffold( appBar: AppBar(title: Text('Users')), body: usersAsync.when( data: (users) => ListView.builder( itemCount: users.length, itemBuilder: (context, index) => ListTile(title: Text(users[index].name)), ), loading: () => Center(child: CircularProgressIndicator()), error: (error, stack) => Center(child: Text('Error: $error')), ), ); }}Configuration
Section titled “Configuration”You can configure query behavior with QueryOptions:
final usersProvider = queryProvider<List<User>>( 'users'.toQueryKey(), () => api.fetchUsers(), options: QueryOptions( staleTime: Duration(minutes: 5), // Marks data as stale after 5 minutes cacheTime: Duration(minutes: 10), // Keeps data in cache for 10 minutes enabled: true, // Set to false to disable auto-fetch refetchOnMount: true, // Whether to refetch when provider is first watched ),);Parameterized Queries
Section titled “Parameterized Queries”Since queryProvider works with standard Riverpod providers, the idiomatic way to handle parameters is to use a function that returns a provider. This ensures type safety and avoids the limitations of the legacy .family pattern.
// Use a function that returns a provider for a specific IDAutoDisposeAsyncNotifierProvider<QueryNotifier<User>, User> userProvider(String userId) { return queryProvider<User>( ['user', userId].toQueryKey(), () => api.fetchUser(userId), options: QueryOptions( staleTime: Duration(minutes: 5), ), );}
class UserDetail extends ConsumerWidget { final String userId; UserDetail(this.userId);
@override Widget build(BuildContext context, WidgetRef ref) { // Watch the specific provider instance final userAsync = ref.watch(userProvider(userId));
return userAsync.when( data: (user) => Text(user.name), loading: () => CircularProgressIndicator(), error: (e, s) => Text('Error'), ); }}Manual Refetching & Invalidation
Section titled “Manual Refetching & Invalidation”The queryProvider notifier exposes methods to manually control the query:
// Refetch the data immediatelyref.read(usersProvider.notifier).refetch();
// Invalidate the cache (marks as stale and refetches if being watched)ref.read(usersProvider.notifier).invalidate();Background Refetching
Section titled “Background Refetching”One of the best features of Fasq is background refetching. When stale data exists in the cache, ref.watch(usersProvider) will return AsyncData containing the cached data, but it will also trigger a background fetch.
You can check if a fetch is happening even if you have data:
final usersAsync = ref.watch(usersProvider);
return Column( children: [ // Show a small indicator during background sync if (usersAsync.isRefreshing) LinearProgressIndicator(),
Expanded( child: usersAsync.when(...) ), ],);[!NOTE]
AsyncValue.isRefreshingis available in Riverpod 2.0+ and istruewhen the provider is being refreshed but still has data.
Dependent Queries
Section titled “Dependent Queries”Queries can depend on other query keys. When a dependent query is invalidated or its data changes, the child query can react.
final userProvider = queryProvider<User>(...);
final postsProvider = queryProvider<List<Post>>( QueryKeys.userPosts(userId), () => api.fetchPosts(userId), dependsOn: QueryKeys.user(userId), // Optional: react to parent query changes);Cancellation Tokens
Section titled “Cancellation Tokens”For long-running fetches that should be cancelled when the widget is disposed, use queryProviderWithToken:
final searchProvider = queryProviderWithToken<List<Result>>( 'search'.toQueryKey(), (token) async { return await api.performSearch(query, cancellationToken: token); },);Next Steps
Section titled “Next Steps”infiniteQueryProvider- Handling large lists with paginationmutationProvider- Managing updates and side effects- Riverpod Patterns - Advanced architectural patterns