#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
виджет выше в иерархии виджетов, если проблема заключается в отдыхе, то это должно помочь.