You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从AsyncValue的error回调中弹出AlertDialog?

处理Riverpod AsyncValue错误状态下弹出AlertDialog的问题

问题描述

使用Riverpod从API加载数据时,希望在API请求失败(AsyncValue处于error状态)时弹出AlertDialog。最初在AsyncValue.when的error回调中直接调用showDialog,运行时触发组件脏状态异常;尝试使用SchedulerBinding.instance.addPostFrameCallback()和context.mounted仍未解决问题。

原始核心代码片段:

final vehiclesList = ref.watch(vehiclesProvider);

// ...

vehiclesList.when(
  // data和loading回调省略
  error: ((error, stackTrace) {
    showDialog(/* ... */);
    return Container();
  }),
)

解决方案

核心问题是不要在build方法内的UI构建回调(如when)中触发弹窗这类副作用——build流程仅负责生成UI,在此期间修改导航栈(弹窗属于导航操作)会导致组件树状态不一致,引发脏状态异常。正确做法是使用ref.listen监听Provider状态变化,在状态变为error时执行弹窗逻辑。

步骤1:用ref.listen监听状态变化

在build方法中添加状态监听,仅当状态从非error变为error时触发弹窗,避免重复弹出:

@override
Widget build(BuildContext context, WidgetRef ref) {
  // 监听vehiclesProvider的状态变化
  ref.listen<AsyncValue<List<Vehicle>>>(vehiclesProvider, (previous, next) {
    // 仅当之前无错误,当前出现错误时才弹窗
    if (previous?.hasError != true && next.hasError) {
      if (context.mounted) { // 确保上下文仍有效
        _showAlertDialog(context);
      }
    }
  });

  final vehiclesList = ref.watch(vehiclesProvider);

  // 后续UI构建逻辑不变
  return Scaffold(/* ... */);
}

步骤2:修改when的error回调

移除when回调中的弹窗逻辑,仅返回错误状态下的UI(如空容器或错误提示):

vehiclesList.when(
  data: (vehicles) { /* 数据展示逻辑 */ },
  error: ((error, stackTrace) {
    // 仅返回UI,不执行副作用
    return const Center(child: Text('加载失败,请稍后重试'));
  }),
  loading: () => const Center(child: CircularProgressIndicator()),
)

步骤3:保留弹窗方法

弹窗方法不变,但要注意使用dialogContext管理弹窗的关闭:

void _showAlertDialog(BuildContext context) {
  showDialog(
    context: context,
    builder: (dialogContext) {
      return AlertDialog(
        title: const Text('提示'),
        content: const Text('车辆列表加载失败,请返回重试'),
        actions: <Widget>[
          TextButton(
            child: const Text('确定'),
            onPressed: () {
              Navigator.of(dialogContext).pop(); // 关闭弹窗
              Navigator.of(context).pop(); // 返回上一页
            },
          ),
        ],
      );
    },
  );
}

关键说明

  • ref.listen是Riverpod专门用于监听状态变化并执行副作用(如弹窗、网络请求)的API,不会干扰build流程,避免脏状态异常。
  • 判断context.mounted可防止上下文已销毁时执行导航操作,避免内存泄漏或异常。
  • 通过对比previous和next的状态,可避免错误状态重复触发时弹窗多次弹出。

内容的提问来源于stack exchange,提问作者realmikep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:57:40