Home > other >  How Can I Escape Multiple Listed Widget (Button) State Management with Flutter Bloc?
How Can I Escape Multiple Listed Widget (Button) State Management with Flutter Bloc?

Time:03-07

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?

More Than One Button State

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 the ListView. This widget is a simple Row 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 into initState.

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).

  • Related