如何基于单个Cubit使用MultiBlocBuilder构建多列表UI?
问题描述
我有一个包含多个列表的HomeCubit,代码如下:
class HomeCubit extends Cubit<HomeState> { final HomeRepository homeRepository; HomeCubit( this.homeRepository, ) : super(HomeInitial()); List<SubCatModal> mySubCat = []; List<SubCatModal> subCat() { emit(HomeLoaded()); homeRepository.getSubCatRepository().then((respone) { emit(HomeSubCatSuccessCase(subCatList: respone)); mySubCat = respone; }); return mySubCat; } List<FirstSlideModal> myFirstSlider = []; List<FirstSlideModal> sliderListCubit() { emit(HomeLoaded()); homeRepository.getFirstSliderRepository().then((respone) { try { emit(HomeFirstSliderSuccessCase(firstSliderList: respone)); } catch (e) { emit(HomeErrorCase(message: respone)); } myFirstSlider = respone; }); return myFirstSlider; } }
路由配置:
case Routes.homeScreen: return MaterialPageRoute( builder: (_) => BlocProvider( create: (BuildContext context) => HomeCubit(HomeRepository(homeApi: HomeApi())), child: const Homepage(), ), );
当前调用方式:
void initState() { super.initState(); var subCubit = BlocProvider.of<HomeCubit>(context).subCat(); }
请问如何通过单个Cubit,使用MultiBlocBuilder分别为myFirstSlider和subCat构建UI?
解决方案
1. 优化状态结构(可选但推荐)
先把分散的状态类梳理清楚,确保每个状态能明确对应数据类型:
abstract class HomeState {} class HomeInitial extends HomeState {} class HomeLoaded extends HomeState {} class HomeSubCatSuccessCase extends HomeState { final List<SubCatModal> subCatList; HomeSubCatSuccessCase({required this.subCatList}); } class HomeFirstSliderSuccessCase extends HomeState { final List<FirstSlideModal> firstSliderList; HomeFirstSliderSuccessCase({required this.firstSliderList}); } class HomeErrorCase extends HomeState { final String message; HomeErrorCase({required this.message}); }
2. 重构Cubit逻辑
去掉返回列表的冗余设计,直接通过emit传递状态,同时合并数据请求的触发方法:
class HomeCubit extends Cubit<HomeState> { final HomeRepository homeRepository; HomeCubit(this.homeRepository) : super(HomeInitial()); // 同时触发分类和轮播数据请求 void fetchAllHomeData() { emit(HomeLoaded()); // 请求分类数据 homeRepository.getSubCatRepository().then((response) { emit(HomeSubCatSuccessCase(subCatList: response)); }).catchError((e) { emit(HomeErrorCase(message: e.toString())); }); // 请求轮播数据 homeRepository.getFirstSliderRepository().then((response) { emit(HomeFirstSliderSuccessCase(firstSliderList: response)); }).catchError((e) { emit(HomeErrorCase(message: e.toString())); }); } }
3. 页面初始化调用统一方法
在Homepage的initState里调用合并后的请求方法:
@override void initState() { super.initState(); BlocProvider.of<HomeCubit>(context).fetchAllHomeData(); }
4. 用MultiBlocBuilder构建UI
MultiBlocBuilder可以监听同一个Cubit的不同状态分支,分别渲染对应UI:
MultiBlocBuilder( bloc: BlocProvider.of<HomeCubit>(context), builder: (context, state) { // 加载状态 if (state is HomeLoaded) { return const Center(child: CircularProgressIndicator()); } // 错误状态 if (state is HomeErrorCase) { return Center(child: Text(state.message)); } // 初始化临时列表存储数据 List<SubCatModal> subCatList = []; List<FirstSlideModal> sliderList = []; // 根据不同状态更新对应列表 if (state is HomeSubCatSuccessCase) { subCatList = state.subCatList; } else if (state is HomeFirstSliderSuccessCase) { sliderList = state.firstSliderList; } return Column( children: [ // 轮播组件,有数据才显示 if (sliderList.isNotEmpty) SliderWidget(sliders: sliderList), // 分类组件,有数据才显示 if (subCatList.isNotEmpty) SubCategoryWidget(subCats: subCatList), ], ); }, )
可选优化:统一成功状态
如果想避免状态分支过多,可改成包含所有数据的统一成功状态,每次更新保留已有数据:
class HomeSuccessState extends HomeState { final List<SubCatModal> subCatList; final List<FirstSlideModal> sliderList; HomeSuccessState({ this.subCatList = const [], this.sliderList = const [], }); // 拷贝方法,仅更新需要修改的部分 HomeSuccessState copyWith({ List<SubCatModal>? subCatList, List<FirstSlideModal>? sliderList, }) { return HomeSuccessState( subCatList: subCatList ?? this.subCatList, sliderList: sliderList ?? this.sliderList, ); } }
对应修改Cubit的emit逻辑:
void fetchAllHomeData() { emit(HomeLoaded()); homeRepository.getSubCatRepository().then((response) { if (state is HomeSuccessState) { emit((state as HomeSuccessState).copyWith(subCatList: response)); } else { emit(HomeSuccessState(subCatList: response)); } }).catchError((e) { emit(HomeErrorCase(message: e.toString())); }); homeRepository.getFirstSliderRepository().then((response) { if (state is HomeSuccessState) { emit((state as HomeSuccessState).copyWith(sliderList: response)); } else { emit(HomeSuccessState(sliderList: response)); } }).catchError((e) { emit(HomeErrorCase(message: e.toString())); }); }
此时UI代码会更简洁:
MultiBlocBuilder( bloc: BlocProvider.of<HomeCubit>(context), builder: (context, state) { if (state is HomeLoaded) { return const Center(child: CircularProgressIndicator()); } if (state is HomeErrorCase) { return Center(child: Text(state.message)); } if (state is HomeSuccessState) { return Column( children: [ SliderWidget(sliders: state.sliderList), SubCategoryWidget(subCats: state.subCatList), ], ); } return const SizedBox(); }, )
内容的提问来源于stack exchange,提问作者Shady Hesham
相关产品推荐
相关产品推荐

