I am managing states using Flutter Bloc. I have a list. When you press the button, it is added to the list by sending a request to the API. Circular Progress Indicator is displayed in case of installation and successful icon in case of completion.
However, the situation changes for all buttons, not the relevant button. How do I change the state of only the button pressed?
return ListView.builder(
itemCount: state.model.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
state.model[index].title ?? "",
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: Text("${state.model[index].subTitle}"),
trailing: BlocConsumer<CarCubit, CarState>(
listener: (context, state) {
if (eatState is CarError) {
final snackBar = SnackBar(
content: Text(state.message ?? ""),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}, builder: (context, state) {
return TextButton(
onPressed: state is CarInitial
? () {
context.read<CarCubit>().addList(
CarModel(
title: state.model[index].title,
category: state.model[index].category,
image: state.model[index].image,
));
}
: null,
child: carStateWidget(state));
}));
});
Widget carStateWidget(CarState state) {
if (state is CarLoading) {
return CircularProgressIndicator(
color: Colors.white,
);
} else if (state is CarCompleted) {
return Icon(
Icons.done,
color: Colors.white,
);
}
return Text(" ", style: TextStyle(color: Colors.white));
}
CodePudding user response:
You can create carId instance to the CarLoading state class and when emitting it just check if the current carId of the loading button of this car object (I have supposed that each car is an object and has a carId instance) matches the received id from the state.
Something like that:
Widget carStateWidget(CarState state, int carId) { // carId
if (state is CarLoading && state.carId == carId) { // check
return CircularProgressIndicator(
color: Colors.white,
);
} else if (state is CarCompleted) {
return Icon(
Icons.done,
color: Colors.white,
);
}
return Text(" ", style: TextStyle(color: Colors.white));
}
Note, don't use methods to create widgets as this is not recommended even officially by flutter team for many reasons, you can check this.
CodePudding user response:
Divide to win ;-)
Create a CarWidget
with its own private cubit:
When a new element is added then a new
CarWidget
is added into theListView
. This widget is a simpleRow
with the car label AND the button.When the user press the button then you can use a cubit to request your API, but note that this cubit is private to this
CarWidget
instance. This cubit can be initialized intoinitState
.
A Cubit
(or a Bloc
) is a state management. As you mentioned each button (or row) must have its own state, so it's better and easier to have its state as close as possible to the widget.
Advantages:
1- It will be impossible to a widget's state to interfere with another widget
2- You won't build the whole tree but only the relevant widget.
3- The user will be able to add multiple cars even without waiting for the previous to complete (which is impossible with your code).