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

如何在单个页面中使用单个Cubit调用多个API并确保全部生效?

单个Cubit调用多个API的问题解决办法

问题分析

  1. 你现在只调用了subCat()方法,没触发SliderListCubit(),自然只有一个API在执行。
  2. 方法里返回列表的逻辑完全无效:API请求是异步操作,then回调里的代码要等请求完成才会执行,你调用方法时直接返回mySubCat/myFirstSlider,这时候它们还是初始空列表,根本拿不到真实数据。
  3. 两个方法都emit了HomeLoaded状态,会导致状态更新冲突,页面无法区分是哪个请求处于加载状态。

解决方案

方案1:统一方法并行调用两个API(推荐)

这么做会同时发起两个API请求,等全部请求完成后emit一个包含所有数据的状态,页面只需处理一次加载完成的逻辑,代码更简洁易维护。

1. 调整Cubit的状态类

创建一个能容纳两类数据的成功状态,同时完善整个状态体系:

abstract class HomeState extends Equatable {
  const HomeState();

  @override
  List<Object> get props => [];
}

class HomeInitial extends HomeState {}

class HomeLoading extends HomeState {}

// 统一的成功状态,包含分类和轮播数据
class HomeDataLoaded extends HomeState {
  final List<SubCatModal> subCatList;
  final List<FirstSlideModal> sliderList;

  const HomeDataLoaded({
    required this.subCatList,
    required this.sliderList,
  });

  @override
  List<Object> get props => [subCatList, sliderList];
}

class HomeError extends HomeState {
  final String errorMsg;

  const HomeError({required this.errorMsg});

  @override
  List<Object> get props => [errorMsg];
}

2. 在Cubit中添加统一的加载方法

删掉原来返回列表的逻辑,改用异步并行请求:

class HomeCubit extends Cubit<HomeState> {
  final HomeRepository homeRepository;

  HomeCubit(this.homeRepository) : super(HomeInitial());

  // 统一加载首页所有数据
  Future<void> fetchAllHomeData() async {
    emit(HomeLoading());
    try {
      // 并行发起两个API请求
      final results = await Future.wait([
        homeRepository.getSubCatRepository(),
        homeRepository.getFirstSliderRepository(),
      ]);
      // 全部请求成功后,emit包含所有数据的状态
      emit(HomeDataLoaded(
        subCatList: results[0],
        sliderList: results[1],
      ));
    } catch (e) {
      emit(HomeError(errorMsg: e.toString()));
    }
  }
}

3. 在页面中调用统一方法

在页面的initState里触发数据加载:

class Homepage extends StatefulWidget {
  const Homepage({super.key});

  @override
  State<Homepage> createState() => _HomepageState();
}

class _HomepageState extends State<Homepage> {
  @override
  void initState() {
    super.initState();
    // 调用统一的加载方法
    BlocProvider.of<HomeCubit>(context).fetchAllHomeData();
  }

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<HomeCubit, HomeState>(
      builder: (context, state) {
        if (state is HomeLoading) {
          return const Center(child: CircularProgressIndicator());
        } else if (state is HomeDataLoaded) {
          // 直接从状态中拿到两类数据,构建页面
          return Column(
            children: [
              SubCatWidget(subCats: state.subCatList),
              SliderWidget(sliders: state.sliderList),
            ],
          );
        } else if (state is HomeError) {
          return Center(child: Text(state.errorMsg));
        } else {
          return const SizedBox();
        }
      },
    );
  }
}

方案2:分开调用两个方法(保留原有状态)

如果需要分别处理两个API的加载状态,可以保留原有状态,但要修正调用逻辑和状态处理方式:

1. 修正Cubit中的方法(移除无用的返回值)

class HomeCubit extends Cubit<HomeState> {
  final HomeRepository homeRepository;
  List<SubCatModal> mySubCat = [];
  List<FirstSlideModal> myFirstSlider = [];

  HomeCubit(this.homeRepository) : super(HomeInitial());

  void loadSubCat() async {
    emit(HomeLoaded());
    try {
      final response = await homeRepository.getSubCatRepository();
      mySubCat = response;
      emit(HomeSubCatSuccessCase(subCatList: response));
    } catch (e) {
      emit(HomeError(errorMsg: e.toString()));
    }
  }

  void loadSlider() async {
    emit(HomeLoaded());
    try {
      final response = await homeRepository.getFirstSliderRepository();
      myFirstSlider = response;
      emit(HomeFirstSliderSuccessCase(firstSliderList: response));
    } catch (e) {
      emit(HomeError(errorMsg: e.toString()));
    }
  }
}

2. 在页面中同时调用两个方法

@override
void initState() {
  super.initState();
  final cubit = BlocProvider.of<HomeCubit>(context);
  cubit.loadSubCat();
  cubit.loadSlider();
}

3. 在BlocBuilder中处理多种状态

BlocBuilder<HomeCubit, HomeState>(
  builder: (context, state) {
    final cubit = context.read<HomeCubit>();
    if (state is HomeLoaded) {
      return const Center(child: CircularProgressIndicator());
    } else if (state is HomeSubCatSuccessCase || state is HomeFirstSliderSuccessCase) {
      // 结合Cubit中保存的两类数据构建页面
      return _buildHomeContent(cubit.mySubCat, cubit.myFirstSlider);
    } else if (state is HomeError) {
      return Center(child: Text(state.errorMsg));
    }
    return const SizedBox();
  },
)

Widget _buildHomeContent(List<SubCatModal> subCats, List<FirstSlideModal> sliders) {
  return Column(
    children: [
      if (sliders.isNotEmpty) SliderWidget(sliders: sliders),
      if (subCats.isNotEmpty) SubCatWidget(subCats: subCats),
    ],
  );
}

关键注意点

  • 绝对不要通过方法返回值获取异步API数据:异步操作完成前返回的都是初始空值,必须通过Cubit的状态来传递数据。
  • 状态类必须继承Equatable:确保Bloc能正确识别状态变化,避免无效刷新。
  • 一定要加错误处理:防止请求失败后页面一直处于无响应状态。

内容的提问来源于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 12:23:15