如何在 riverpod future provider 中抛出错误并在错误发生时捕获它
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);
}
}
我试图在 riverpod future provider 中抛出自定义异常并在其他状态通知程序中捕获异常 类,但未触发 catch 块。
有没有其他方法来处理未来提供者抛出的异常。
首先,您不必手动捕获 FutureProvider
中的错误,它会为您完成。 Refer this example.
一般来说,在某些“用户交互”之后发生的操作,如单击按钮(在本例中为登录操作),并不意味着要写在 FutureProvider
中。您将使用 FutureProvider
的场景如下:
- 正在通过 HTTP/HTTPS 获取一些数据。
- 执行读取文件或本地数据库等操作。
所以您的登录用例可以使用 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());
然后,在你的UI部分,通常在按钮的onTap / onPressed
事件处理程序中,你可以按如下方式使用它。请注意,我们创建了一个扩展 ConsumerWidget
以访问 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,
);
}
}
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);
}
}
我试图在 riverpod future provider 中抛出自定义异常并在其他状态通知程序中捕获异常 类,但未触发 catch 块。 有没有其他方法来处理未来提供者抛出的异常。
首先,您不必手动捕获 FutureProvider
中的错误,它会为您完成。 Refer this example.
一般来说,在某些“用户交互”之后发生的操作,如单击按钮(在本例中为登录操作),并不意味着要写在 FutureProvider
中。您将使用 FutureProvider
的场景如下:
- 正在通过 HTTP/HTTPS 获取一些数据。
- 执行读取文件或本地数据库等操作。
所以您的登录用例可以使用 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());
然后,在你的UI部分,通常在按钮的onTap / onPressed
事件处理程序中,你可以按如下方式使用它。请注意,我们创建了一个扩展 ConsumerWidget
以访问 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,
);
}
}