Reputation: 83
I am trying to handle 3 different states in my app, in the initState of my home, I call the event "OnInitial" pretending to be a method that fetches data from the local DB.
As you can see in the method on I am setting "6" to the variable "number" as I said, pretending that this would be the data that I brought from the DB. My event finishes fetching the data and emits the state "ProductsTercero" already with "the data assigned".
In my home, if the state is ProductsTercero I paint a column with the "msg" and the "number". When inital finishes my screen is redrawn correctly and shows
But my problem is the following. When I press the button called "Tercero" that triggers the event "OnTercero" In my Bloc, when this event is called, it sets a 'New msg' to the variable "msg" of ProducsTercero. What does this? the next:
It removes the "number 6" that I had set before, that is, regarding the simulation, I would be deleting all the data that I brought from the DB.
my expected result was:
New msg
6
but i got
New msg
0
I debug and it seems like it's always creating a new ProductsThird object. even if I do ProductsTercero().copyWith(msg: 'New msg'); is the same.
I have worked with only 1 state and this does not happen to me, because I always do a state.copyWith(); and the other values of that state are always maintained no matter if i pass 1 attribute of 5 attributes it has. but here, having more than one state and having an abstract state class, I can't write emit(state.copyWith(msg: 'New msg');
What am I doing wrong? What would be the correct way to emit on X state and that this does not happen?
Event, state and bloc code:
part of 'products_bloc.dart';
@immutable
abstract class ProductsEvent {}
class OnInitial extends ProductsEvent {}
class OnSegundo extends ProductsEvent {}
class OnTercero extends ProductsEvent {}
//**************************************************************//
part of 'products_bloc.dart';
@immutable
abstract class ProductsState {}
class ProductsInitial extends ProductsState {
final String? msg;
final int? numero;
ProductsInitial({numero, msg})
: msg = msg ?? 'MSG: Default Inicial',
numero = numero ?? 0;
ProductsInitial copywith({String? msg, int? numero}) =>
ProductsInitial(msg: msg ?? this.msg, numero: numero ?? this.numero);
}
class ProductsSegundo extends ProductsState {
final String? msg;
final int? numero;
ProductsSegundo({numero, msg})
: msg = msg ?? 'Second: Default Msg',
numero = numero ?? 0;
ProductsSegundo copywith({String? msg, int? numero}) =>
ProductsSegundo(msg: msg ?? this.msg, numero: numero ?? this.numero);
}
class ProductsTercero extends ProductsState {
final String? msg;
final int? numero;
ProductsTercero({numero, msg})
: msg = msg ?? 'Third: Default Msg',
numero = numero ?? 0;
ProductsTercero copywith({String? msg, int? numero}) =>
ProductsTercero(msg: msg ?? this.msg, numero: numero ?? this.numero);
}
//**********************************************************//
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
part 'products_event.dart';
part 'products_state.dart';
class ProductsBloc extends Bloc<ProductsEvent, ProductsState> {
ProductsBloc() : super(ProductsInitial()) {
on<OnInitial>((event, emit) {
emit(ProductsInitial().copywith(
msg: 'Initial msg'
));
emit(ProductsTercero(numero: 6));
});
on<OnSegundo>((event, emit) {
emit(ProductsSegundo());
});
on<OnTercero>((event, emit) {
emit(ProductsTercero(msg: 'New msg'));
});
}
}
Homepage code:
import 'package:bloc_test/src/bloc/products/products_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
BlocProvider.of<ProductsBloc>(context).add(OnInitial());
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<ProductsBloc, ProductsState>(
builder: (context, state) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
(state is ProductsInitial) ? Column(
children: [
Center(child: Text(state.msg!)),
Center(child: Text(state.numero!.toString())),
],
)
: (state is ProductsSegundo) ? Column(
children: [
Center(child: Text(state.msg!)),
Center(child: Text(state.numero!.toString())),
],
)
: (state is ProductsTercero) ? Column(
children: [
Center(child: Text(state.msg!)),
Center(child: Text(state.numero!.toString())),
],
)
: Center(child: Text('Nada')),
SizedBox(
height: 40,
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
ElevatedButton(
onPressed: () {
BlocProvider.of<ProductsBloc>(context).add(OnInitial());
},
child: Text('Initial')),
ElevatedButton(
onPressed: () {
BlocProvider.of<ProductsBloc>(context).add(OnSegundo());
},
child: Text('Segundo')),
ElevatedButton(
onPressed: () {
BlocProvider.of<ProductsBloc>(context).add(OnTercero());
},
child: Text('Tercero'))
],
),
),
],
),
);
},
);
}
}
Upvotes: 3
Views: 4214
Reputation: 1632
You are creating a new state object with each event. You want to copy the existing state.
on<OnTercero>((event, emit) {
emit(state.copyWith(msg: 'New msg'));
}
Upvotes: 0
Reputation: 11
You are not passing num value on emit(ProductsTercero(msg: 'New msg'));
Since num == null then it is set to 0, as defined by your code.
Try Replacing like below
on<OnTercero>((event, emit) {
emit(ProductsTercero(msg: 'New msg',numero: 6));
});
Upvotes: 1