mutate `currentState` property in flutter_bloc
Solution 1
The flutter bloc requires you to yield a new instance of the state, instead of modifying the currentState.
So I made the following changes in the below classes.
class Employee extends Equatable {
int id;
String name;
double salery;
Employee(this.id, this.name, this.salery) : super([id, name, salery]);
Employee copyWith({
String name,
double salery,
}) {
return Employee(this.id, name ?? this.name, salery ?? this.salery);
}
@override
String toString() {
return 'Employee { id: $id, name: $name, salery: $salery }';
}
}
Modified the mapEventToState method and added one helper method to update the list propertites.
@override
Stream<List<Employee>> mapEventToState(EmployeeEvent event) async* {
yield this.updateList(event);
}
Stream<EmployeeState> updateList(EmployeeEvent event) async* {
final id = (currentState as EmployeeLoaded).employee[event.index].id;
List<Employee> employeeUpdate =
(currentState as EmployeeLoaded).employee.map((employee) {
if (employee.id == id) {
return employee.copyWith(
salery: (event is IncrementEvent)
? employee.salery + 200
: employee.salery - 200);
}
return employee;
}).toList();
print((currentState as EmployeeLoaded).employee == employeeUpdate);
print(currentState == EmployeeLoaded(employeeUpdate));
yield EmployeeLoaded(employeeUpdate);
}
Solution 2
Your main problem is that you don't have any class that represent your state. So first you should create needed states. You can use simple examples provided in the bloc
website.
And for the global understanding :
The BlocBuilder
will rebuild only on these case (With equatable
):
- The instance runtime type of the new and the old state are different
- The instance of the new and the old state are the same instance type it will deeply compare all nested properties of the previous and the new state to know what have changed by calling
==
. - You can also use
conditional
property function that you provide on creation.
If you want to use the same instance you can extends Equatable
(from equatable
package here) or do the same thing it's doing. (this medium post can help you).
With your case you can do this :
abstract class EmployeeState extends Equatable {
EmployeeState([List props = const []]) : super(props);
@override
String toString() => '$runtimeType{}';
}
class EmployeeLoaded extends EmployeeState{
EmployeeLoaded(this.employees):super([employees])
final List<Employee> employees;
}
For further info/help you can come on the bloc
gitter.
Anirudha Mahale
Curious as to how these mobile apps worked the way they do, Almost immediately, I grabbed a chance and started off as an iOS mobile developer. And there it is, I knew this is what i wanted to do with my life! A Combo of creative and analytical skills gets me do better everyday. Definitely there is always more to learn and thats my passion. I have 5+ years of experience in designing, developing, project analysis and management in the field of mobile application development being iOS at my best.
Updated on December 12, 2022Comments
-
Anirudha Mahale over 1 year
I have a flutter app in which I display list of employees with by their name and salery in listView widget. I have two buttons for each employee to increase or decrease their salery.
I am using flutter_bloc for state management.
Here is the Employee class.
class Employee extends Equatable { int _id; String _name; double _salery; Employee(this._id, this._name, this._salery); // setters set id(int id) { this._id = id; } set name(String name) { this._name = name; } set salery(double salery) { this._salery = salery; } // getters int get id => this._id; String get name => this._name; double get salery => this._salery; }
Here is the class as event.
@immutable abstract class EmployeeEvent { final int _index; EmployeeEvent(this._index); int get index => this._index; } class IncrementEvent extends EmployeeEvent { IncrementEvent(int index) : super(index); } class DecrementEvent extends EmployeeEvent { DecrementEvent(int index) : super(index); }
Here is the bloc class which handles the state.
class EmployeeBloc extends Bloc<EmployeeEvent, List<Employee>> { @override List<Employee> get initialState => [ Employee(1, 'Employee One', 10000.0), Employee(2, 'Employee Two', 10000.0), Employee(3, 'Employee Three', 10000.0), Employee(4, 'Employee Four', 10000.0), Employee(5, 'Employee Five', 10000.0), ]; @override Stream<List<Employee>> mapEventToState(EmployeeEvent event) async* { // I have checked, the control reaches over here. double currentSalery = currentState[event.index].salery; if (event is IncrementEvent) { // Increments the salery when user presses the increment button currentState[event.index].salery = currentSalery + (currentSalery * 0.2); } else if (event is DecrementEvent) { currentState[event.index].salery = currentSalery - (currentSalery * 0.2); } print(currentState[event.index].salery); // even prints the incremented / decremented salery. yield currentState; } }
After yielding, the
BlocBuilder
from the widget class isn't called.If I change the method like this then it calls
BlocBuilder
but I cann't increment or decrement the salery of employee at particular index.@override Stream<List<Employee>> mapEventToState(EmployeeEvent event) async* { if (event is IncrementEvent) { yield currentState; } else if (event is DecrementEvent) { yield currentState; } }
How do I increment or decrement the salery of particular employee at particular index?