Проверка состояния блока с помощью blockbuilder

#flutter #dart #bloc

#трепетание #дротик #блок

Вопрос:

Я извлекаю список элементов из API и создаю их с помощью blockbuilder. Это работает, и список виджетов создается, но когда я распечатываю, чтобы проверить, какая часть состояния выполняется, я получаю, как показано ниже. Почему появилось «Ничего»?

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

Обновить

Добавлен код блока для справки.

Блок

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

  }
}
 

Комментарии:

1. можете ли вы также поделиться своими событиями, состояниями и блоками? для краткости: Nothing появляется потому, что вы пропустили одно возможное состояние, которое вы получаете от блока. если вы поймаете это состояние с помощью другого оператора if, то вы ничего не увидите.

2. смотрите обновление. спасибо @Mahdi-Jafaree

3. вы улавливаете все состояния, но не улавливаете ProductLoading состояние внутри вашего blocBuilder , которое прослушивает новые состояния. просто добавьте if( state is ProductLoading) и обработайте его, после Nothing чего он не будет напечатан, так как вы улавливаете все состояния.

Ответ №1:

Обновите свой блок с помощью приведенного ниже кода:

БЛОК

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

Как и в вашем коде, вы находитесь ProductLoading в состоянии yield, но не обрабатывали это состояние в своем blockbuilder, поэтому он обходит все операторы if и ничего не печатает.

Итак, другой способ — это обработка 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();
              }
            )
          )
        );
      }
 

Комментарии:

1. @stalwart1014 дайте мне знать, если это не сработает для вас

2. Я думаю, что нет необходимости уступать ProductInitial() в первый раз, поскольку блок сам справится с этим.

3. @Mahdi-Jafaree да, верно, вот почему я добавил два варианта, чтобы исправить эту проблему.