简体   繁体   中英

How to throw error inside riverpod future provider and catch it on error flutter

final loginProvider =
    FutureProvider.family<bool, LoginParam>((ref, param) async {
  if (param.sgId == '' || param.password == '') {
    return false;
  }
  final http.Response response =
      await APIClient().login(param.sgId, param.password);
  if (response.statusCode == 200) {
    await APIClient().saveTokens(response);
    UserDefaultEntity entity =
        await ref.watch(userDefaultsProvider(param.sgId).future);
    //ref.state = AsyncValue.data(true);
    return true;
  } else {
    throw Exception(jsonDecode(response.body)['message'] ?? 'Unknown Error');
  }
});
  void login(String userName, String password) async {
    state = AsyncValue.loading();
    AsyncValue<bool> result;
    try {
      result = await ref.refresh(loginProvider(LoginParam(userName, password)));
      state = result;
    } catch (e) {
      state = AsyncError(e);
    }
  }

I'm trying to throw an custom exception inside riverpod future provider and catch the exception in other state notifier classes, but the catch block is not triggered. Is there any other way to handle exceptions that future provider throw.

First of all, you won't have to manually catch errors inside a FutureProvider , it will do that for you. Refer this example .

Generally, the operations that happen after certain "user interaction" like a button click (in this case, login operation), are not meant to be written in FutureProvider . Scenarios where you'd be using FutureProvider are as follows:

  • Fetching some data over HTTP/HTTPS.
  • Performing operations like reading a file or a local database.

So your use case of login can be achieved using a StateNotifier .

// auth_provider.dart

import 'package:hooks_riverpod/hooks_riverpod.dart';

// Always prefer some strongly typed object to 
// know current status of authentication.
enum AuthState {
  unauthenticated,
  authenticated,
  authenticating,
  failed,
}

// StateNotifier is recommended to encapsulate all your business
// logic into a single class and use it from there.
class AuthStateNotifier extends StateNotifier<AuthState> {
  // Initialize with the default state of "unauthenticated".
  const AuthStateNotifier() : super(AuthState.unauthenticated);

  Future<void> login(LoginParam params) async {
    if (param.sgId.isEmpty || param.password.isEmpty) {
      state = AuthState.failed;
      return;
    }

    final http.Response response = await APIClient().login(param.sgId, param.password);

    if (response.statusCode == 200) {
      await APIClient().saveTokens(response);
      UserDefaultEntity entity = await ref.watch(userDefaultsProvider(param.sgId).future);
      state = AuthState.authenticated;
      return;
    } else {
      state = AuthState.failed;
      throw Exception(jsonDecode(response.body)['message'] ?? 'Unknown Error');
    }
  }
}

// Finally, create a provider that can be consumed in the presentation layer (UI).
final authProvider = StateNotifierProvider<AuthStateNotifier, AuthState>((ref) => const AuthStateNotifier());

Then, in your UI part, usually in the onTap / onPressed event handler of button, you can use it as follows. Please note that, we have created a button widget that extends the ConsumerWidget to access the ref .

// login.dart

import 'auth_provider.dart';

class LoginButton extends ConsumerWidget {
  final LoginParam params;

  const LoginButton({
    Key? key,
    required this.params,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    void login() {
      try {
        await ref.read(authProvider.notifier).login(params);
      } catch (e) {
        // Handle error here.
      }
    }

    return ElevatedButton(
      child: Text('Login'),
      // Call the handler here.
      onPressed: login,
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM