使用 blocbuilder 检查 bloc 状态

Posted

技术标签:

【中文标题】使用 blocbuilder 检查 bloc 状态【英文标题】:Checking bloc state with blocbuilder 【发布时间】:2021-03-19 11:27:22 【问题描述】:

我正在从 API 获取项目列表并使用 BlocBuilder 构建它们。它可以工作并且构建了小部件列表,但是当我打印出来检查正在执行的状态部分时,我得到如下所示。为什么会出现“Nothing”?

ProductInitial
fetching product //from bloc when fetching api
Nothing
fetching complete //from bloc after fetching api
ProductSuccess

主要

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MultiBlocProvider(
        providers: [
          BlocProvider<ProductBloc>(
            create: (BuildContext context) => ProductBloc()..add(FetchProduct())
          ),
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          home: MainScreen(),
        )
      );
  

列表屏幕

Widget build(BuildContext context) 
    return Container(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: BlocBuilder<ProductBloc, ProductState>(
          builder: (context, state) 
            if(state is ProductInitial)
              print('ProductInitial');
              return buildLoadingWidget();
            
            if(state is ProductSuccess)
              print('ProductSuccess');
              return _buildProductListWidget(state.products);
            
            if(state is ProductFailed)
              print('ProductFailed');
              return Center(
                child: Text('Something went wrong'),
              );
            
            print('Nothing');
            return buildLoadingWidget();
          
        )
      )
    );
  

更新

添加了bloc代码以供参考。

集团

class ProductBloc extends Bloc<ProductEvent, ProductState> 
  ProductBloc() : super(ProductInitial());

  ProductRepository _repository = ProductRepository();

  @override
  Stream<ProductState> mapEventToState(ProductEvent event,) async* 
    
    if(event is FetchProduct)
      yield ProductLoading();
      try
        print('fetching product');
        final List<ProductModel> products = await _repository.getProducts();
        yield ProductSuccess(products);
        print('fetching complete');
      catch(e)
        yield ProductFailed();
        print(e);
        print('fetching failed');
      
    

  

【问题讨论】:

您也可以分享您的活动、州和集团吗?简短的回答:Nothing 出现是因为您错过了您从集团让步的一种可能状态。如果您使用另一个 if 语句捕获该状态,那么您将看不到任何内容。 查看更新。谢谢@Mahdi-Jafaree 您正在捕获所有状态,但未捕获 blocBuilder 中正在侦听新状态的 ProductLoading 状态。只需添加一个if( state is ProductLoading) 并处理它,然后Nothing 将不会被打印,因为您正在捕获所有状态。 【参考方案1】:

使用以下代码更新您的集团:

BLOC

class ProductBloc extends Bloc<ProductEvent, ProductState> 
ProductBloc() : super(ProductInitial());
   
 ProductRepository _repository = ProductRepository();

  @override
  Stream<ProductState> mapEventToState(ProductEvent event,) async* 
    
    if(event is FetchProduct)
      yield ProductInitial();
      try
        print('fetching product');
        final List<ProductModel> products = await _repository.getProducts();
        yield ProductSuccess(products);
        print('fetching complete');
      catch(e)
        yield ProductFailed();
        print(e);
        print('fetching failed');
      
    
  

在您的代码中,您处于 yield ProductLoading 状态,但没有在 BlocBuilder 中处理该状态,这就是它绕过所有 if 语句并打印 Nothing 的原因。

所以另一种方法是在你的块构建中处理ProductLoading,如下所示

列表屏幕

  Widget build(BuildContext context) 
        return Container(
          child: Padding(
            padding: EdgeInsets.all(10.0),
            child: BlocBuilder<ProductBloc, ProductState>(
              builder: (context, state) 
                if(state is ProductInitial)
                  print('ProductInitial');
                  return buildLoadingWidget();
                
                if(state is ProductLoading)
                  print('ProductLoading');
                  return buildLoadingWidget();
                
                if(state is ProductSuccess)
                  print('ProductSuccess');
                  return _buildProductListWidget(state.products);
                
                if(state is ProductFailed)
                  print('ProductFailed');
                  return Center(
                    child: Text('Something went wrong'),
                  );
                
                print('Nothing');
                return buildLoadingWidget();
              
            )
          )
        );
      

【讨论】:

@stalwart1014 如果这不适合你,请告诉我 我认为没有必要在第一次提交ProductInitial(),因为 bloc 自己会处理它。 @Mahdi-Jafaree 是的,这就是为什么我添加了两个选项来纠正这个问题。

以上是关于使用 blocbuilder 检查 bloc 状态的主要内容,如果未能解决你的问题,请参考以下文章

Flutter bloc:更新状态不会重新调用 BlocBuilder

Flutter Bloc:更新后未调用 BlocBuilder,ListView 仍显示旧数据

flutter_bloc 的 BlocBuilder 能否避免重建 Widget 的未更改部分?

使用相同 Bloc/Cubit 的多个 BlocBuilder,每个 BlocBuilder 用于不同的事件

动画切换器和 Bloc Builder

Bloc - 是不是可以在导航堆栈中为上一页产生状态?