Search code examples
flutterdartcubitflutter-cubit

Proper use of cubit


I am still learning how to use cubits and blocs, and I am trying to use a cubit in my project, but I got a little bit confused about how to use it.

There is a screen that requires a phone number and I use the lib "intl_phone_number_input" to format, validate and select the country. When I click the button to the next page it needs to check if the phone is valid, but I need to have a variable that stores this info. The widget InternationalPhoneNumberInput has a property onInputValidated that returns true if the phone number is valid, so where should I create this variable? Should I create it in my widget class or inside the cubit? I created it inside cubit but I am not sure if it is the correct way, so I got this:

onInputValidated: (bool value) {
  BlocProvider.of<LoginCubit>(context).isValid =
    value;
},

I've studied and seen some examples about cubits and how to use'em but I still didn't get it at all, because in the examples the cubit never used a variable, all variables became a state, but in my case, I need the value as a variable.

I am confused too about how to show a dialog using cubit, I've done it this way:

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<LoginCubit, LoginState>(
      listenWhen: (previous, current) => current is ShowDialogErrorLoginState || current is NavigateFromLoginStateToHomePageState,
      listener: (context, state) {
        if (state is ShowDialogErrorLoginState) {
          showErrorDialog(context, state.titleMessage, state.bodyMessage);
        }
        if (state is NavigateFromLoginStateToHomePageState) {
          Navigator.pushReplacement(context,
              MaterialPageRoute(builder: (context) => const MyHomePage()));
        }
      },
      builder: (context, state) {
        if (state is ShowLoginState) {
          return buildPhoneForm(context);
        }
        if (state is SendingCodeLoginState) {
          return ProgressView(message: 'Sending SMS code',);
        }
        if (state is ShowCodeLoginState) {
          return buildCodeForm(context);
        }
        return const ErrorView('Unknown error');
      },
    );
  }

and in my cubit I did the following:

  void goToCodeVerification(String phoneNumber) async {
    if (!isValid){
      String titleMessage = "Phone number invalid";
      String bodyMessage = "The given phone number is invalid";

      emit(ShowDialogErrorLoginState(titleMessage, bodyMessage));
      emit(ShowLoginState());
    } else {
      emit(SendingCodeLoginState());
      // TO DO
      // use API to send a code
      emit(ShowCodeLoginState());
    }
  }

Is this the correct way to show a dialog with a cubit?


Solution

  • Ok, so you have a value you want to use, the variable doesn't affect state, and you need to access it inside your cubit.

    for something like this, I think storing the variable on the cubit makes the most sense, but keep in mind either approach is acceptable for such a simple case.

    I also don't really like how the below code looks:

    onInputValidated: (bool value) {
      BlocProvider.of<LoginCubit>(context).isValid =
        value;
    },
    

    it is a bit clunky, I would prefer to move the whole callback into the cubit:

    void onInputValidated(bool value) => isValid = value;
    

    that way:

    final cubit = BlocProvider.of<LoginCubit>(context);
    ...
    onInputValidated: cubit.onInputValidated,