Flutter/Dart使用dartz的Either时如何弹出对话框而非返回Widget
问题原因
- 你当前的报错核心来自两个不符合Flutter开发规范的写法:
Either.fold要求左右分支返回完全相同的类型,你在错误分支仅调用showDialog没有返回Widget,触发编译类型校验错误。- 弹窗属于副作用操作,不能放在Widget的
build方法中执行——build方法会在状态变化时多次重复执行,直接写在build里会导致弹窗重复弹出,也不符合纯渲染逻辑的设计原则。
最优解决方案:使用Riverpod状态监听器处理副作用
这是最符合Riverpod设计规范的实现方式,通过ref.listen监听状态变化,仅在请求完成的回调中判断是否需要弹出错误弹窗,渲染逻辑只负责返回对应状态的Widget即可。
代码修改点
1. 调整渲染逻辑,添加状态监听器
修改HomePage中第一个Consumer的代码:
Consumer( builder: (ctx, ref, child) { // 注册状态监听器,仅在请求状态变为loaded时触发一次 ref.listen<NotifierState>( notifier.select((notifier) => notifier.state), (previous, next) { if (next == NotifierState.loaded) { ref.read(notifier).post.fold( (failure) { // 弹窗逻辑移到这里执行,不涉及渲染返回值 showDialog( context: ctx, barrierDismissible: true, builder: (BuildContext context) => AlertDialog( title: Text(failure.toString()), ), ); }, // 成功分支不需要操作直接留空即可 (_) {}, ); } }, ); // 纯渲染逻辑,所有分支都返回Widget if (ref.watch(notifier).state == NotifierState.initial) { return const Text('Press the button'); } else if (ref.watch(notifier).state == NotifierState.loading) { return const CircularProgressIndicator(); } else { return ref.read(notifier).post.fold( // 错误分支随便返回一个占位Widget即可,不需要展示错误状态就返回SizedBox.shrink() (failure) => const SizedBox.shrink(), (post) => Text(post.toString()), ); } }, ),
备选方案:在点击事件中直接处理请求结果
如果你不想用监听器,也可以修改PostChangeNotifier的getOnePost方法,让它直接返回请求结果,在按钮点击的异步回调中判断是否弹出错误:
1. 修改PostChangeNotifier的getOnePost方法
// 修改返回值类型为Future<Either<Failure, Post?>> Future<Either<Failure, Post?>> getOnePost() async { _setState(NotifierState.loading); final result = await Task(() => _postService.getOnePost()) .attempt() .mapLeftToFailure() .run() as Either<Failure, Post?>; _setPost(result); _setState(NotifierState.loaded); // 返回请求结果 return result; }
2. 修改按钮点击逻辑
ElevatedButton( onPressed: () async { // 等待请求完成,直接处理结果 final result = await ref.read(notifier).getOnePost(); result.fold( (failure) => showDialog( context: ctx, barrierDismissible: true, builder: (BuildContext context) => AlertDialog( title: Text(failure.toString()), ), ), (_) {}, ); }, child: const Text('Get Post'), )
核心逻辑说明
Either本身是纯数据类型,和UI操作没有绑定,你遇到的问题本质是把副作用写在了错误的位置,只要把弹窗这类非渲染逻辑移到事件回调、状态监听器这类专门处理副作用的位置,就可以和Either的错误处理完美配合。
内容的提问来源于stack exchange,提问作者RobbB
相关产品推荐
相关产品推荐

