本文介绍了Flutter Riverpod StateNotifierProvider:仅监视模型一部分的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这样的模型:

class TimerModel {
  const TimerModel(this.timeLeft, this.buttonState);
  final String timeLeft;
  final ButtonState buttonState;
}

enum ButtonState {
  initial,
  started,
  paused,
  finished,
}

这是StateNotifierProvider:

And here is the 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());

但是,我想创建另一个仅侦听ButtonState中的更改的提供程序.这不起作用:

However I want to make another provider that only listens for changes in the ButtonState. This doesn't work:

final buttonProvider = StateProvider<ButtonState>((ref) {
  return ref.watch(timerProvider.state).buttonState;
});

因为它仍然返回所有状态更改.

because it still returns all the state changes.

这也不起作用:

final buttonProvider = StateProvider<ButtonState>((ref) {
  return ref.watch(timerProvider.state.buttonState);
});

因为 state 对象没有 buttonState 属性.

我如何仅观看buttonState的更改?

How do I only watch buttonState changes?

推荐答案

每当监视状态更改时,使用 watch 都会给出一个新状态.这样可以分两部分解决问题:

Using watch gives a new state whenever the watched state changes. So can solve the problem in two parts like so:

final _buttonState = Provider<ButtonState>((ref) {
  return ref.watch(timerProvider.state).buttonState;
});

每次 timerProvider.state 更改时,使用此提供程序都会导致重建.但是,诀窍是执行以下操作:

Using this provider will cause a rebuild every time the timerProvider.state changes. However, the trick is to do the following:

final buttonProvider = Provider<ButtonState>((ref) {
  return ref.watch(_buttonState);
});

由于 _buttonState 对于大多数 timerProvider.state 都是相同的,因此观看 _buttonState 只会在 _buttonState时引起重建实际上会发生变化.

Since _buttonState will be the same for most of the timerProvider.state changes, watching _buttonState will only cause rebuilds when _buttonState actually changes.

感谢这篇文章显示了答案.该帖子还表明不久将有一个简化的语法:

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));

这篇关于Flutter Riverpod StateNotifierProvider:仅监视模型一部分的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-18 04:56
查看更多