Skip to Content

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

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

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

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)

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

Update query options at runtime (e.g., enable/disable fetching, change stale time). This will automatically swap the underlying query if necessary.

// Pause fetching context.read<UsersQueryCubit>().updateOptions( newOptions: QueryOptions(enabled: false), ); // Resume fetching with new stale time context.read<UsersQueryCubit>().updateOptions( newOptions: QueryOptions( enabled: true, staleTime: Duration(seconds: 30), ), );

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

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

Trigger manual refetches using the Cubit:

context.read<UsersQueryCubit>().refetch();

Next Steps

Last updated on