You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于单个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 14:22:33