[英]Flutter Riverpod StateNotifierProvider: only watch changes for part of a model
I have a model like this:我有一个这样的模型:
class TimerModel {
const TimerModel(this.timeLeft, this.buttonState);
final String timeLeft;
final ButtonState buttonState;
}
enum ButtonState {
initial,
started,
paused,
finished,
}
And here is the StateNotifierProvider:这是 StateNotifierProvider:
class TimerNotifier extends StateNotifier<TimerModel> {
TimerNotifier() : super(_initialState);
static const int _initialDuration = 10;
static final _initialState = TimerModel(
_durationString(_initialDuration),
ButtonState.initial,
);
final Ticker _ticker = Ticker();
StreamSubscription<int> _tickerSubscription;
void start() {
if (state.buttonState == ButtonState.paused) {
_tickerSubscription?.resume();
state = TimerModel(state.timeLeft, ButtonState.started);
} else {
_tickerSubscription?.cancel();
_tickerSubscription =
_ticker.tick(ticks: _initialDuration).listen((duration) {
state = TimerModel(_durationString(duration), ButtonState.started);
});
_tickerSubscription.onDone(() {
state = TimerModel(state.timeLeft, ButtonState.finished);
});
state =
TimerModel(_durationString(_initialDuration), ButtonState.started);
}
}
static String _durationString(int duration) {
final String minutesStr =
((duration / 60) % 60).floor().toString().padLeft(2, '0');
final String secondsStr =
(duration % 60).floor().toString().padLeft(2, '0');
return '$minutesStr:$secondsStr';
}
void pause() {
_tickerSubscription?.pause();
state = TimerModel(state.timeLeft, ButtonState.paused);
}
void reset() {
_tickerSubscription?.cancel();
state = _initialState;
}
@override
void dispose() {
_tickerSubscription?.cancel();
super.dispose();
}
}
class Ticker {
Stream<int> tick({int ticks}) {
return Stream.periodic(Duration(seconds: 1), (x) => ticks - x - 1)
.take(ticks);
}
}
I can listen for all changes in state like this:我可以像这样监听状态的所有变化:
final timerProvider = StateNotifierProvider<TimerNotifier>((ref) => TimerNotifier());
However I want to make another provider that only listens for changes in the ButtonState.但是,我想创建另一个仅侦听 ButtonState 更改的提供程序。 This doesn't work:这不起作用:
final buttonProvider = StateProvider<ButtonState>((ref) {
return ref.watch(timerProvider.state).buttonState;
});
because it still returns all the state changes.因为它仍然返回所有状态更改。
This also doesn't work:这也不起作用:
final buttonProvider = StateProvider<ButtonState>((ref) {
return ref.watch(timerProvider.state.buttonState);
});
Because the state
object doesn't have a buttonState
property.因为state
对象没有buttonState
属性。
How do I only watch buttonState changes?我如何只观看 buttonState 的变化?
Using watch
gives a new state whenever the watched state changes.每当被监视的状态改变时,使用watch
会给出一个新的状态。 So can solve the problem in two parts like so:所以可以像这样分两部分解决问题:
final _buttonState = Provider<ButtonState>((ref) {
return ref.watch(timerProvider.state).buttonState;
});
Using this provider will cause a rebuild every time the timerProvider.state
changes.每次timerProvider.state
更改时,使用此提供程序都会导致重建。 However, the trick is to do the following:但是,诀窍是执行以下操作:
final buttonProvider = Provider<ButtonState>((ref) {
return ref.watch(_buttonState);
});
Since _buttonState
will be the same for most of the timerProvider.state
changes, watching _buttonState
will only cause rebuilds when _buttonState
actually changes.由于大多数timerProvider.state
更改的_buttonState
将相同,因此观察_buttonState
只会在_buttonState
实际更改时导致重建。
Thanks to this post for showing the answer.感谢这篇文章给出了答案。 That post also indicates that there will be a simplified syntax soon:该帖子还表明很快就会有一个简化的语法:
final buttonState = ref.watch(timerProvider.state.select((state) => state.buttonState));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.