Dependent Queries (Bloc)
Create queries that depend on other queries by extending QueryCubit and implementing conditional logic.
Basic Dependent Query
Section titled “Basic Dependent Query”class UserPostsQueryCubit extends QueryCubit<List<Post>> { final String userId;
UserPostsQueryCubit(this.userId);
@override String get key => 'posts:user:$userId';
@override Future<List<Post>> Function() get queryFn => () => api.fetchUserPosts(userId);
@override QueryOptions? get options => QueryOptions( enabled: userId.isNotEmpty, );}
class UserPostsScreen extends StatelessWidget { final String userId;
const UserPostsScreen({required this.userId});
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('User Posts')), body: MultiBlocProvider( providers: [ BlocProvider(create: (context) => UserProfileQueryCubit(userId)), BlocProvider(create: (context) => UserPostsQueryCubit(userId)), ], child: BlocBuilder<UserProfileQueryCubit, QueryState<User>>( builder: (context, userState) { if (userState.isLoading) { return Center(child: CircularProgressIndicator()); }
if (!userState.hasData) { return Center(child: Text('User not found')); }
final postsCubit = context.read<UserPostsQueryCubit>(); if (userState.hasData && postsCubit.state.isIdle) { postsCubit.refetch(); }
return BlocBuilder<UserPostsQueryCubit, QueryState<List<Post>>>( builder: (context, postsState) { if (postsState.isLoading) { return Center(child: Text('Loading posts...')); }
if (postsState.hasData) { return PostsList(posts: postsState.data!); }
return SizedBox(); }, ); }, ), ), ); }}Conditional Enabling
Section titled “Conditional Enabling”Use the enabled option to control when queries execute:
class CategoryProductsQueryCubit extends QueryCubit<List<Product>> { final int? categoryId;
CategoryProductsQueryCubit(this.categoryId);
@override String get key => 'products:category:$categoryId';
@override Future<List<Product>> Function() get queryFn => () => api.fetchProducts(categoryId!);
@override QueryOptions? get options => QueryOptions( enabled: categoryId != null, );}Dynamic Dependencies
Section titled “Dynamic Dependencies”Create queries with dynamic dependencies based on parent query state:
class UserDashboardScreen extends StatelessWidget { final String userId;
const UserDashboardScreen({required this.userId});
@override Widget build(BuildContext context) { return Scaffold( body: MultiBlocProvider( providers: [ BlocProvider(create: (context) => UserProfileQueryCubit(userId)), BlocProvider(create: (context) => UserPostsQueryCubit(userId)), BlocProvider(create: (context) => UserFollowersQueryCubit(userId)), ], child: BlocBuilder<UserProfileQueryCubit, QueryState<User>>( builder: (context, userState) { if (userState.isLoading) { return Center(child: CircularProgressIndicator()); }
if (!userState.hasData) { return Center(child: Text('User not found')); }
final user = userState.data!;
return Column( children: [ UserHeader(user: user), Expanded( child: Row( children: [ Expanded( child: BlocBuilder<UserPostsQueryCubit, QueryState<List<Post>>>( builder: (context, postsState) { return PostsList(posts: postsState.data ?? []); }, ), ), Expanded( child: BlocBuilder<UserFollowersQueryCubit, QueryState<List<User>>>( builder: (context, followersState) { return FollowersList(followers: followersState.data ?? []); }, ), ), ], ), ), ], ); }, ), ), ); }}Next Steps
Section titled “Next Steps”- QueryCubit - Learn about the QueryCubit
- Bloc Patterns - Best practices
- Examples - Complete working examples