Предотвращение сброса значения в блоке

#flutter #dart #bloc

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

Вопрос:

У меня есть 2 экрана, 1 экран товара и 1 экран корзины. На экране товара просто отображается весь товар, и когда пользователь нажимает кнопку добавить в корзину, запускается событие AddToCart. Проблема в том, что я продолжаю получать сообщение «Корзина пуста». и переменная cart в блоке cart продолжает сбрасываться на [], когда я переключаюсь между товаром и экраном корзины.

Главный экран

 MultiBlocProvider(
    providers: [
      BlocProvider<ProductBloc>(
        create: (BuildContext context) => ProductBloc()..add(FetchProduct()),
      ),
      BlocProvider<CartBloc>(
        create: (BuildContext context) => CartBloc()..add(FetchCart()),
      ),
    ],
)
 

Состояние корзины

 abstract class CartState extends Equatable {
  const CartState();
  @override
  List<Object> get props => [];
}
class CartInitial extends CartState {}
class CartLoading extends CartState {}
class CartSuccess extends CartState {
  final List<ProductModel> carts;
  const CartSuccess(this.carts);
  @override
  List<Object> get props => [carts];
}
class CartFailed extends CartState {}
 

Событие Корзины

 abstract class CartEvent extends Equatable {
  const CartEvent();
  @override
  List<Object> get props => [];
}
class FetchCart extends CartEvent {}
class AddToCart extends CartEvent {
  final ProductModel product;
  const AddToCart(this.product);
  @override
  List<Object> get props => [product];
}
class RemoveFromCart extends CartEvent {
  final ProductModel product;
  const RemoveFromCart(this.product);
  @override
  List<Object> get props => [product];
}
 

Блок корзины

 class CartBloc extends Bloc<CartEvent, CartState> {
  CartBloc() : super(CartInitial());

  List<ProductModel> carts = []; // always resets

  Stream<CartState> mapEventToState(CartEvent event) async* {

    print(carts);

    if(event is FetchCart){
        yield CartSuccess(carts);
        print(carts.length);
    }

    if(event is AddToCart){
      try{
        carts.add(event.product);
        yield CartSuccess(carts);
        print(carts.length);
      }catch(e){
        yield CartFailed();
        print(e);
      }
    }

    if(event is RemoveFromCart){
      try{
        carts.remove(event.product);
        yield CartSuccess(carts);
      }catch(e){
        yield CartFailed();
        print(e);
      }
    }

  }
}
 

Экран Корзины

   Widget build(BuildContext context) {
    return Container(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: BlocBuilder<CartBloc, CartState>(
          builder: (context, state) {
            if(state is CartInitial){
              print('CartInitial');
              return buildLoadingWidget();
            }
            if(state is CartSuccess){
              print('CartSuccess');
              if(state.carts.length == 0)
                return Center(
                  child: Text('Cart is empty.',style: TextStyle(color: Colors.white,)
                ));
              else
                return _buildProductListWidget(state.carts);
            }
            if(state is CartFailed){
              print('CartFailed');
              return Center(
                child: Text('Something went wrong'),
              );
            }
            return buildLoadingWidget();
          }
        )
      ),
    );
  }
 

Ответ №1:

Я думаю, это связано с тем, что вызывается метод сборки главного экрана, и внутри поставщиков создаются новые экземпляры блоков. Лучше использовать переменную для этих блоков, например, вместо ProductBloc()..add(FetchProduct()), использования переменной,

 final productBloc = ProductBloc();

initState(){
   productBloc.add(FetchProduct());
}

//Then in the provider,
MultiBlocProvider(
    providers: [
      BlocProvider<ProductBloc>(
        create: (BuildContext context) => productBloc,
      ),
      
    ],
)
 

Таким образом, он не будет создавать новые блоки, вместо этого он будет использовать тот же, который создан и сохранен в переменной.

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

1. Подобный код не является хорошей идеей, потому что, если предыдущий блок удален, он productBloc также удалит экземпляр. Тогда BlockProvider будет создан новый экземпляр с недопустимым экземпляром блока.

2. Я знаю, что пользователь может удалить блок, перезаписав метод dispose, или в этом случае вы должны использовать виджет без состояния, чтобы метод сборки не вызывался снова. или во время навигации используйте maintainState: true , если это поможет

Ответ №2:

Похоже, что код в порядке, а проблема где-то в другом месте. Возможно, вы воссоздаете блок при каждом переключении страницы или что-то в этом роде. Вы можете добавить инструкцию print в CartBloc constructor, а затем переключить страницу и посмотреть в консоли эти инструкции. Таким образом, вы можете попытаться найти неправильное место таким образом. Или вы можете обновить сообщение дополнительным кодом, чтобы кто-то мог понять, что в нем не так. Также вы можете попытаться переместить свой MultiBlocProvider виджет выше в иерархии виджетов, если проблема заключается в отдыхе, то это должно помочь.