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
相关产品推荐
相关产品推荐

