How to handle errors with ValueNotifier

265

Well, probably not the most optimal, but the solution I gave to this problem was to create a second valueNotifier to propagate custom exceptions as:

abstract class CustomException implements Exception {
  final String message; // Note that this message is for logging not displaying to the user

  CustomException(this.message);
}

class ExampleAuthException extends CustomException {
  final int remainingAttempts;

  ExampleAuthException({required this.remainingAttempts, required String message}) : super(message);
}
class ErrorNotifier extends ValueNotifier<CustomException?> {
  ErrorNotifier(CustomException? value) : super(value);
}
class ViewState{
final ErrorNotifier errorNotifier;
final LoginStateNotifier loginState;
...
}

I make it nullable as to now when there are no errors, and I use this as a second communication channel.

Share:
265
Darrell
Author by

Darrell

Updated on December 22, 2022

Comments

  • Darrell
    Darrell over 1 year

    I have a ValueNotifier class that performs some logic, then alerts all listeners when done. The problem I have is how to alert the listeners when there is an error in the processing so that an appropriate message can be displayed in the UI.

    Here is the ValueNotifier class:

    class LoginStateNotifier extends ValueNotifier<LoggedInStates> {
      LoginStateNotifier(LoggedInStates value) : super(value);
    
      Future<void> login({required String email, required String password}) async {
        try {
          final userCredential = await FirebaseAuth.instance
              .signInWithEmailAndPassword(email: email, password: password);
    
          print(userCredential);
        } on FirebaseAuthException catch (e) {
          switch (e.code) {
            case "invalid-email":
              throw (Constants.invalidEmail);
            case "user-disabled":
              throw (Constants.userDisabled);
            case "user-not-found":
              throw (Constants.userNotFound);
            case "wrong-password":
              throw (Constants.wrongPassword);
            default:
              throw ("${e.code} is an invalid FirebaseAuth exception");
          }
        } catch (e) {
          throw ("DEBUG: ${e.toString()} - occurred in login()");
        }
      }
    
      Future<void> logOut() async {
        await FirebaseAuth.instance.signOut();
      }
    } 
    

    Here is the widget in the UI that is listening for changes:

            ValueListenableBuilder<LoggedInStates>(
              valueListenable: _loginScreenController.loginStateNotifier,
              builder: (context, loggedInStates, child) {
                return loggedInStates == LoggedInStates.loggedIn
                    ? Text(
                        'Logged In',
                        style: Theme.of(context).textTheme.headline2,
                      )
                    : Text(
                        'Logged Out',
                        style: Theme.of(context).textTheme.headline2,
                      );
              },
            ),
    

    I just need a way for the listener to know when errors occur as well, not just when the value changes.

  • Darrell
    Darrell almost 3 years
    thanks a lot. that worked. but, i wonder if there is a solution that doesn't require another notifier, such as what's used in pub.dev/packages/error_notifier_for_provider?
  • croxx5f
    croxx5f almost 3 years
    Well other solutions that come to my mind are using streams or futures that communicate errors or using discriminated unions like Either or Result (see dartz) that model an object as having two possible states and you could use something like Either<LoggedInStates,CustomException> as the value of your notifier. What are your thoughts on this @Darrell
  • Darrell
    Darrell almost 3 years
    This is my first Flutter app, so those solutions seem fairly complex and what you provided is easily understood and work. So, I will continue with your original solution for now and make note of the others for future reference as my experience grows.