Flutter Riverpod中StreamProvider与FutureProvider组合重复重建问题
现象原因
- 核心触发点是你在
FutureProvider f的构造函数中使用了ref.watch(s.last):s.last是StreamProvider内置派生的FutureProvider,它会跟随StreamProvider的状态变化而更新。当StreamProvider s首次加载状态从loading变为携带true的data状态时,ref.watch会监听到状态变化,强制触发f的整个异步逻辑重新执行,因此出现两次打印。 autoDispose特性会放大这个问题:在f的异步函数等待ref.watch(s.last)完成的过程中,f暂时没有可用的输出状态,临时没有监听者持有f的引用时,s的监听器会被短暂销毁重建,也会额外触发一次逻辑执行。
解决方案
下面两种方案都可以保证逻辑仅执行一次:
方案1:使用ref.read代替ref.watch
如果你仅需要一次性获取流的值,不需要后续跟随流的状态更新,直接读取last的值即可,不需要监听变化:
final f = FutureProvider.autoDispose<bool>((ref) async { // 把watch换成read,不会监听状态变化,仅执行一次 final source = await ref.read(s.last); print('Stream value received: $source'); return source; });
方案2:监听StreamProvider的原生状态做防抖处理
如果你需要跟随流的新值更新状态,但要保证每个流值仅执行一次业务逻辑,可以直接监听StreamProvider的AsyncValue,仅在值变化时执行逻辑:
import 'dart:async'; final f = FutureProvider.autoDispose<bool>((ref) async { final streamValue = ref.watch(s); return streamValue.when( loading: () async { // 等待流首次发出值 final completer = Completer<bool>(); StreamSubscription? sub; sub = ref.read(s.stream).listen((event) { completer.complete(event); sub?.cancel(); }); final value = await completer.future; print('Stream value received: $value'); return value; }, data: (value) { print('Stream value received: $value'); return value; }, error: (e, st) => throw e, ); });
内容的提问来源于stack exchange,提问作者András Szepesházi
相关产品推荐
相关产品推荐

