I'm creating a Flutter application. I'm added a BloC to my project for management state. I created a list with data. And I want to add item to ListView manually with button 'Add'.
I'm wrote a code:
My Item Cubit
class ItemCubit extends Cubit<List<Item>> {
ItemCubit() : super([]);
void addItem(item){
state.add(item);
emit(state);
}
}
Page of Items with Provider:
class SearchPage extends StatelessWidget {
const SearchPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (_) => ItemCubit(),
child: Search(),
),
);
}
}
And I call the BlocBuilder in Stateless Widget like this:
body: BlocBuilder<MarketCubit, List<Market>>(
builder: (context, items) => TabBarView(...))
So when I call my function from state:
Item item = Item(1, 'Item 1');
ElevatedButton(onPressed:(){
context.read<ItemCubit>().addItem(item);
}, child: Text('Add Item')),
The ListView doesn't updating. What's problem? Thanks a lot!
The problem is that you are just adding the item to the state and re-emitting the same (modified) list. Bloc will essentially check the value of the state object to see if it is a new object when you call emit(), if it is the 'same list' as the last state, it will do nothing. It is confusing because even though you are adding a new value to the list, it is still the same object in a sense, just with a new value.
So there should be an easy fix if you just create a new list instead of modifying the original one and emit that.
For example, this should fix the issue:
emit([...state, newValue])
or
final newList = List.from(state)..add(newValue);
emit(newList);
(I had trouble finding in the bloc documentation where this is explained, but there are a number of issue threads where it is discussed -https://github.com/felangel/bloc/issues/2374)
Essentially, the state should be 'immutable', so if you are going to emit a new state, you should actually create a new instance of whatever you are going to emit. The way I typically use the state is to have a class with final fields for whatever state the cubit is tracking, and a copyWith method that makes it easy to create a new instance with any modified fields:
YourCubitState{
final List stateList;
final otherField;
const YourCubitState({
this.stateList = [],
this.otherField,
});
YourCubitState copyWith({
List? stateList,
otherField,
}) =>
YourCubitState(
stateList: stateList ?? this.stateList,
otherField: otherField ?? this.otherField,
);
}
Maybe that is unnecessary if the state is just a single list, but if you find yourself wanting to add properties to the state, that is a good pattern to follow.
create new variable, add them to the new variable list, update your new variable list item to it, emit the data with the new variable. this is how i got it working.
late List<ServicesExpensesList> newList = <ServicesExpensesList>[];
state.utilityDataList.forEach((element) {
newList.add(element);
});
newList.insert(0, utilityData);
newList.sort((a, b) => b.createdAt.compareTo(a.createdAt));
emit(state.copyWith(
utilityDataList: newList,
status: state.status == BlocStateStatus.success
? BlocStateStatus.updated
: BlocStateStatus.success,
))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With