如何使用Riverpod让ProgressNotifier监听BatchSizeNotifier变更并自重置?
问题描述
当BatchSizeNotifier的状态发生变更时,希望ProgressNotifier通过监听前者的变化自行执行重置操作,但当前实现无法生效。如何使用Riverpod让Provider正确响应其他Provider的变化?
现有代码
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:zero_loss_compress/convertion_stats.dart'; final batchSizeProvider = NotifierProvider<BatchSizeNotifier, int>(() { return BatchSizeNotifier(); }); final progressProvider = NotifierProvider<ProgressNotifier, int>(() { return ProgressNotifier(); }); class BatchSizeNotifier extends Notifier<int> { @override int build() { return 0; } void setBatchSizeAndResetConversionState( int batchSize, WidgetRef ref, ) { state = batchSize; // 希望移除这个调用,让ProgressNotifier自行监听重置 // ref.read(progressProvider.notifier).reset(); ref.read(convertionStatsStateProvider.notifier).state = ConvertionStats(0, 0); } } class ProgressNotifier extends Notifier<int> { @override int build() { ref.listen(batchSizeProvider, (previous, next) { reset(); }); return 0; } void increment() { state = state + 1; } void reset() { state = 0; } }
解决方案
当前写法失效的核心原因:ProgressNotifier的build方法只有在progressProvider被UI或其他Provider订阅时才会执行,否则其中的ref.listen不会注册监听。同时,即使注册了监听,初始构建时也可能误触发重置。可以通过以下两种方式修复:
方式一:通过ref.watch建立依赖,自动重置
在ProgressNotifier的build方法中读取batchSizeProvider,让progressProvider直接依赖前者的状态。当batchSize变化时,build会重新执行,直接返回初始值实现重置:
class ProgressNotifier extends Notifier<int> { @override int build() { // 建立对batchSizeProvider的依赖,状态变化时触发build重执行 ref.watch(batchSizeProvider); // 每次batchSize变更,重置进度为0 return 0; } void increment() { state = state + 1; } void reset() { state = 0; } }
方式二:用ref.listen精细控制重置时机
如果需要区分初始构建和后续状态变更(比如初始时不执行重置),可以保留ref.listen并添加判断逻辑:
class ProgressNotifier extends Notifier<int> { @override int build() { ref.listen(batchSizeProvider, (previous, next) { // 只有当batchSize从已有值变更时,才执行重置 if (previous != null) { reset(); } }); return 0; } void increment() { state = state + 1; } void reset() { state = 0; } }
额外注意事项
- 确保
BatchSizeNotifier中state = batchSize的更新逻辑正确,Riverpod会自动过滤相同值的状态更新,只有当新值与当前state不同时,才会触发依赖通知。 - 如果
progressProvider从未被任何地方订阅,上述两种方式都不会生效。需要确保UI或其他Provider中使用了ref.watch(progressProvider)或类似方法订阅它。
内容的提问来源于stack exchange,提问作者Fractale
相关产品推荐
相关产品推荐

