Riverpod:API错误时如何在输入框下方正确显示错误信息
解决方案
你的问题核心是混合了本地状态(isError)和Riverpod控制器状态,导致状态不同步,且AsyncNotifier的错误状态不会自动重置。下面是符合声明式编程的优雅解决方案:
1. 优化控制器:自定义异常+添加状态重置方法
首先给控制器添加自定义异常(避免字符串匹配异常的脆弱性),并新增清除错误状态的方法:
// submit_controller.dart class InvalidOtpException implements Exception {} class SubmitController extends AsyncNotifier<void> { @override FutureOr<void> build() {} Future<void> submit(String otp) async { // 每次提交先进入loading状态,重置之前的错误 state = const AsyncValue.loading(); try { // 替换为实际的API调用 await Future.delayed(const Duration(seconds: 3)); // 模拟OTP验证失败 throw InvalidOtpException(); } on InvalidOtpException catch (error, stackTrace) { // 仅捕获OTP无效的异常 state = AsyncError(error, stackTrace); } catch (error, stackTrace) { // 处理其他未知异常 state = AsyncError(error, stackTrace); } } // 清除错误状态,用于用户输入时重置 void clearError() { if (state.hasError) { state = const AsyncData(null); } } }
2. 重构页面:移除本地状态,依赖控制器单一数据源
去掉页面中的isError本地状态,直接从控制器状态读取错误信息,同时在用户输入时触发状态重置:
// main.dart class HomePage extends ConsumerStatefulWidget { const HomePage({super.key}); @override ConsumerState<HomePage> createState() => _HomePageState(); } class _HomePageState extends ConsumerState<HomePage> { final TextEditingController controller = TextEditingController(); @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final submitState = ref.watch(submitControllerProvider); return Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( enabled: !submitState.isLoading, controller: controller, onChanged: (_) { // 用户输入时立即清除错误状态 ref.read(submitControllerProvider.notifier).clearError(); }, ), // 根据控制器状态直接渲染错误信息 if (submitState.error is InvalidOtpException) const Text( 'Invalid OTP', style: TextStyle(color: Colors.red), ) else const SizedBox.shrink(), TextButton( // loading时禁用按钮,防止重复提交 onPressed: submitState.isLoading ? null : () { ref.read(submitControllerProvider.notifier).submit(controller.text); }, child: const Text('Submit'), ), ], ), ), ); } }
关键改进点
- 单一数据源:所有状态由Riverpod控制器管理,避免本地状态和控制器状态不一致的问题。
- 声明式渲染:错误信息的显示完全依赖控制器的状态,无需手动维护
isError变量。 - 状态自动同步:用户输入时主动重置控制器的错误状态,确保输入时错误信息立即消失。
- 健壮的异常处理:用自定义异常替代字符串匹配,避免后续异常信息修改导致的逻辑失效。
内容的提问来源于stack exchange,提问作者Syed Ahmed Jamil
相关产品推荐
相关产品推荐

