QueryCubit
The QueryCubit is an abstract base class that wraps a Fasq query, emitting QueryState changes. Extend QueryCubit to create your own query cubits with type-safe, structured state management.
Basic Usage
Section titled “Basic Usage”Extend QueryCubit and implement the required getters:
import 'package:flutter/material.dart';import 'package:flutter_bloc/flutter_bloc.dart';import 'package:fasq_bloc/fasq_bloc.dart';
class UsersQueryCubit extends QueryCubit<List<User>> { @override QueryKey get queryKey => 'users'.toQueryKey();
@override Future<List<User>> Function() get queryFn => () => api.fetchUsers();}
class UsersScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Users')), body: BlocProvider( create: (context) => UsersQueryCubit(), child: BlocBuilder<UsersQueryCubit, QueryState<List<User>>>( builder: (context, state) { if (state.isLoading) { return Center(child: CircularProgressIndicator()); }
if (state.hasError) { return Center(child: Text('Error: ${state.error}')); }
if (state.hasData) { return ListView.builder( itemCount: state.data!.length, itemBuilder: (context, index) { final user = state.data![index]; return ListTile(title: Text(user.name)); }, ); }
return Center(child: Text('No users found.')); }, ), ), ); }}Cubit Configuration
Section titled “Cubit Configuration”Configure query behavior by overriding the options getter:
class UsersQueryCubit extends QueryCubit<List<User>> { @override QueryKey get queryKey => 'users'.toQueryKey();
@override Future<List<User>> Function() get queryFn => () => api.fetchUsers();
@override QueryOptions? get options => QueryOptions( staleTime: Duration(minutes: 5), cacheTime: Duration(minutes: 10), enabled: true, onSuccess: () { print('Users fetched successfully'); }, onError: (error) { print('Error fetching users: $error'); }, );}Advanced Features
Section titled “Advanced Features”Cancellation
Section titled “Cancellation”Cancel an in-flight query without closing the Cubit. This is cooperative cancellation, meaning your queryFn must check the cancellation token.
context.read<UsersQueryCubit>().cancel();Manual Cache Updates (Optimistic UI)
Section titled “Manual Cache Updates (Optimistic UI)”You can manually set the data for a query immediately. This is useful for optimistic UI patterns or syncing local state.
final newUser = User(id: '123', name: 'New User');context.read<UsersQueryCubit>().setData([newUser]);Dynamic Configuration
Section titled “Dynamic Configuration”Update query options at runtime (e.g., enable/disable fetching, change stale time). This will automatically swap the underlying query if necessary.
// Pause fetchingcontext.read<UsersQueryCubit>().updateOptions( newOptions: QueryOptions(enabled: false),);
// Resume fetching with new stale timecontext.read<UsersQueryCubit>().updateOptions( newOptions: QueryOptions( enabled: true, staleTime: Duration(seconds: 30), ),);Parameterized Queries
Section titled “Parameterized Queries”Use constructor parameters or fields for dynamic query keys:
class UserProfileQueryCubit extends QueryCubit<User> { final String userId;
UserProfileQueryCubit(this.userId);
@override QueryKey get queryKey => 'user:$userId'.toQueryKey();
@override Future<User> Function() get queryFn => () => api.fetchUser(userId);}Conditional Queries
Section titled “Conditional Queries”Disable queries based on conditions using the enabled option:
class UserProfileQueryCubit extends QueryCubit<User?> { final String? userId;
UserProfileQueryCubit(this.userId);
@override QueryKey get queryKey => 'user:$userId'.toQueryKey();
@override Future<User?> Function() get queryFn => () => api.fetchUser(userId!);
@override QueryOptions? get options => QueryOptions( enabled: userId != null, );}Manual Refetching
Section titled “Manual Refetching”Trigger manual refetches using the Cubit:
context.read<UsersQueryCubit>().refetch();Next Steps
Section titled “Next Steps”- MutationCubit - Learn about mutations
- Composition - Manage multiple queries
- Bloc Patterns - Best practices
- Examples - Complete working examples