skip to Main Content

I have a provider which throws an exception which I want to handle where I read the provider:

@Riverpod(dependencies: [firebaseAuth])
User currentUser(CurrentUserRef ref) {
  final user = ref.watch(firebaseAuthProvider).currentUser;
  if (user == null) {
    throw UserNotSignedInException();
  }
  return user;
}

and I want to catch it here:

try {
  ref.read(currentUserProvider);
  resolver.next();
} on UserNotSignedInException {
  logger('User is not logged in, pushing intro route');
  router.push(const IntroRoute());
}

But the Exception is thrown inside the provider and never reaches the catch block. Does somebody know how to pass the exception so I can handle it in the try catch? I know when using AsyncValue that I get an AsyncError to handle but I don’t want an async provider.

2

Answers


  1. Chosen as BEST ANSWER

    In my case it made most sense to just throw the Exception inside the try catch block. I want to do this because I want to make sure that a user is logged in and don't want to handle a nullable User object.

    @override
    void onNavigation(NavigationResolver resolver, StackRouter router) {
      try {
        final user = ref.watch(firebaseAuthProvider).currentUser;
        if (user == null) {
          throw UserNotSignedInException();
        }
        resolver.next();
      } on UserNotSignedInException {
        logger('User is not logged in, pushing intro route', name: 'IntroGuard');
        router.push(const IntroRoute());
      } catch (e, s) {
        logger(
          'Error navigating to intro route',
          error: e,
          stackTrace: s,
          name: 'IntroGuard',
        );
        router.push(const IntroRoute());
      }
    }
    

  2. You could wrap your User object inside an UserState object with both the User and the Exception or Èrror.

    For example something like this:

    class UserState {
      final User? user;
      final Error? error;
    
      final get bool isOk => user != null && error == null;
    
      UserState.success(required this.user);
      UserState.error(required this.error);
    }
    

    And then in your code:

    @Riverpod(dependencies: [firebaseAuth])
    UserState currentUser(CurrentUserRef ref) {
      final user = ref.watch(firebaseAuthProvider).currentUser;
      if (user == null) {
        return UserState.error(UserNotSignedInException())
      }
      return UserState.success(user);
    }
    

    and

    final userState = ref.read(currentUserProvider);
    if (state.isOk) {
      resolver.next();
    } else {
      logger('User is not logged in, pushing intro route');
      router.push(const IntroRoute());
    }
    

    This way, your provider always returns a valid state, whether the User could be obtained or not.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search