Skip to content

Dependent Queries (Bloc)

Create queries that depend on other queries by extending QueryCubit and implementing conditional logic.

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();
},
);
},
),
),
);
}
}

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,
);
}

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 ?? []);
},
),
),
],
),
),
],
);
},
),
),
);
}
}