How to add multiple state in one cubit in flutter bloc pattern?
Asked Answered
P

2

5

I was developing an application in flutter which does OTP based authentication to log in. Earlier I was managing the states in the class itself so that I can use the setState method to render the UI accordingly. Then I changed into flutter_bloc cubit pattern to manage the states. But I fail to understand that how can I keep track of multiple states in one cubit.

Consider the following code of State and Cubit,


**State**.

@immutable
abstract class LoginState {}

class LoginInitial extends LoginState {
  final Map loginState;
  LoginInitial({this.loginState});
}

**Cubit**
class LoginCubit extends Cubit<LoginState> {
  Map loginState = {
    "isPhoneSubmitted": false,
    "isOtpArrived": false,
  };
  LoginCubit()
      : super(
          LoginInitial(
            loginState: {
              "isPhoneSubmitted": false,
              "isOtpArrived": false,
            },
          ),
        );

  void sendOtp() {
    emit(
      LoginInitial(
        loginState: {
          "isPhoneSubmitted": true,
          "isOtpArrived": false,
        },
      ),
    );
    Future.delayed(Duration(seconds: 4), () {
      emit(
        LoginInitial(
          loginState: {
            "isPhoneSubmitted": true,
            "isOtpArrived": true,
          },
        ),
      );
    });
  }
}

Here, Initially, I'm setting both values inside the map as false. And when the user clicks on the button setting the isPhoneSubmitted to true. And a few seconds later isOtpArrived to true(In future after getting OTP). However, I don't think this is the right approach to implement the pattern. Consider If I have 10 properties in a class and I'm sending a map of 10 properties each time when emit method is called.

Can someone help me understand or implement the best practice to hold/update multiple states to the widget the Cubit is listening to?

Also, in the widget, this is how I'm listening to the changes,

 BlocBuilder<LoginCubit, LoginState>(builder: (context, state) {
                final data = (state as LoginInitial).loginState;
                if (!data["isPhoneSubmitted"]) {
                  return phoneNumberSubmitWidget();
                } else {
                  return codeVerificationWidget();
                }
              }),
Pave answered 25/5, 2021 at 7:36 Comment(8)
As you said this is not a right approach. Go thorough bloclibrary.dev/#/gettingstarted and the tutorials for better understanding of the bloc state managementYecies
you can listen to the state in the builder function. change your if statement to (state is MyState) after that the builder should get updated when the state changes. If that answers your question?Incrocci
Thank you for your comment @SilkeNL. If I use the state is MyState approach which can actually have one state manipulated in different state classes. Even then how can I keep track of multiple state values. If I manipulate one property next time it changes to another.Pave
as @nvoigt 's answer says, it might be better to use Bloc instead of Cubit. Then you can yield different states. Change back and forth between maybe a loading and loaded state. Then your widget will be updated every state change.Incrocci
Yes, @SilkeNL. I have gone through and going to implement the bloc itself. Actually, I'm using the flutter_bloc library. In their documentation, only a cubit example is there. I was following so many guides and very much confused. Even for bloc, many are using flutter_bloc and many are directly writing from scratch. It's actually so much confusing that my app will go very complex in future.Pave
Do you have a chat program where I can send you some sample code?Incrocci
yeah ... no, lol, not whatsapp. Maybe something like discord? My user is: SilkeNL#2967 (And I would edit your comment to not add your phone number)Incrocci
Oh my bad. I have created an account in discord. My user is : musthafapa7#2539Pave
O
8

However, I don't think this is the right approach to implement the pattern.

You are correct. The first step for complex state switches is to not use Cubit but an actual Bloc. Cubits are meant for very simple data with basically no state flow logic at all. Like an int. Or maybe a DarkTheme/LightTheme switch. Or maybe the language, where it can only ever be one and exactly one.

But you have a complex flow. With "in-between" states. So use a Bloc and read the tutorial on this, in this case probable the login tutorial.

Oxley answered 25/5, 2021 at 8:12 Comment(2)
Thanks, @Oxley for the suggestion. I'm trying to implement the bloc itself instead of using cubits. However, the above example is very complex and will lead me to have a lot of boiler plate codes. If possible can you provide me with an example that uses the flutter_bloc library in an easy way.Pave
Use snippets to generate the boiler plate codes faster @PaveKokaras
V
0

here is an example about how to deal with multiple states: if you use cubit or bloc the states do not change. This is a weather app that was part of a training class. The class did the same app in cubit and then bloc and used this method for the states. The states file never changes. Using the enum the TempUnit (UI switch) can toggle the state between C or F. Here is the state file - can be used, without changing, if you change to a bloc. You can find the completed project here: https://github.com/AllyTechEngineering/open_weather_cubit

    part of 'temp_settings_cubit.dart';

enum TempUnit {
  celsius,
  fahrenheit,
}

class TempSettingsState extends Equatable {
  final TempUnit tempUnit;
  TempSettingsState({
    this.tempUnit = TempUnit.celsius,
  });

  factory TempSettingsState.initial() {
    return TempSettingsState();
  }
// Method overriding using @overide is the practice of a child class redefining a method inherited from its parent class.
// this method is used to check if the objects are the same or !same.
  @override
  List<Object> get props {
    return [tempUnit];
  }

  @override
  String toString() => 'TempSettingsState(tempUnit: $tempUnit)';


  TempSettingsState copyWith({
    TempUnit? tempUnit,
  }) {
    return TempSettingsState(
      tempUnit: tempUnit ?? this.tempUnit,
    );
  }
}

Here is the related cubit file:

    import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

part 'temp_settings_state.dart';

class TempSettingsCubit extends Cubit<TempSettingsState> {
  TempSettingsCubit() : super(TempSettingsState.initial());

  void toggleTempUnit() {
    emit(
      state.copyWith(
        tempUnit: state.tempUnit == TempUnit.celsius ? TempUnit.fahrenheit : TempUnit.celsius,
      ),
    );
    // print('TempSettingsCubit tempUnit; $state');
  } //void toggleTempUnit
} //class TempSettingsCubit
Vaniavanilla answered 2/11, 2023 at 11:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.