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

Flutter Riverpod构建时更新StateProvider触发异常求助

解决方案

核心原因

在ReadArticleW的build方法中,当FutureProvider返回数据时直接调用ref.read(isSavedVider.notifier).state = isSaved,属于在组件构建流程中修改状态。此时Flutter正在构建ReadArticleW,修改状态会触发依赖isSavedVider的ReadTopBarW立即重建,打破了Flutter的构建顺序,因此抛出异常。

修复方案

方案1:延迟状态更新到构建完成后

使用WidgetsBinding.instance.addPostFrameCallback,把状态更新逻辑放到当前帧构建完成后执行,避免在构建流程中修改状态:

data: (datax) {
  final decodedData = json.decode(datax.body);
  final isSaved = decodedData[1].toString();
  // 延迟到当前帧构建完成后更新状态
  WidgetsBinding.instance.addPostFrameCallback((_) {
    ref.read(isSavedVider.notifier).state = isSaved;
  });
  return Column(
    children: [
      Text(decodedData[0]['articleTitle'].toString()),
      Image.network(decodedData[0]['articleLImage'].toString()),
    ],
  );
},

方案2:合并状态逻辑(更推荐)

既然isSaved的值完全来自singleArticleFProvider的接口响应,没必要单独用StateProvider存储。直接在ReadTopBarW中监听singleArticleFProvider,提取isSaved值即可,简化状态管理:

class ReadTopBarW extends ConsumerWidget {
  const ReadTopBarW({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final futureArticle = ref.watch(singleArticleFProvider);
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        InkWell(
            onTap: () => Navigator.pop(context),
            child: const Icon(Icons.arrow_back_ios)),
        Row(
          children: [
            futureArticle.when(
              data: (datax) {
                final decodedData = json.decode(datax.body);
                final isSaved = decodedData[1].toString();
                // 根据接口返回值切换图标
                return isSaved == "1" 
                    ? const Icon(Icons.bookmark_outlined) 
                    : const Icon(Icons.bookmark_border);
              },
              error: (_, __) => const Icon(Icons.bookmark_border),
              loading: () => const Icon(Icons.bookmark_border),
            ),
            const SizedBox(width: 10),
            const Icon(Icons.ios_share),
          ],
        ),
      ],
    );
  }
}

修改后可以直接删除isSavedVider这个StateProvider,避免不必要的状态同步问题。

方案3:支持本地修改状态的场景

如果后续需要用户手动切换收藏状态(不仅依赖接口初始值),可以将ReadArticleW改为StatefulWidget,在initState中监听FutureProvider的结果并更新状态:

class ReadArticleW extends StatefulWidget {
  const ReadArticleW({Key? key}) : super(key: key);

  @override
  State<ReadArticleW> createState() => _ReadArticleWState();
}

class _ReadArticleWState extends State<ReadArticleW> {
  @override
  void initState() {
    super.initState();
    // 延迟到组件初始化完成后处理状态更新
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final ref = ProviderScope.containerOf(context);
      ref.watch(singleArticleFProvider).whenData((datax) {
        final decodedData = json.decode(datax.body);
        final isSaved = decodedData[1].toString();
        ref.read(isSavedVider.notifier).state = isSaved;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    final ref = ProviderScope.containerOf(context);
    final futureCatFacts = ref.watch(singleArticleFProvider);
    return SingleChildScrollView(
      child: futureCatFacts.when(
        data: (datax) {
          final decodedData = json.decode(datax.body);
          return Column(
            children: [
              Text(decodedData[0]['articleTitle'].toString()),
              Image.network(decodedData[0]['articleLImage'].toString()),
            ],
          );
        },
        error: (err, stack) => Text('Error: $err'),
        loading: () => const ShimmerReadW(),
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:24:47