Почему должен быть реализован UpdateWidget для подписок и ChangeNotifiers? - PullRequest
0 голосов
/ 23 марта 2020

Я создал собственный виджет, который прослушивает ChangeNotifier и вызывает предоставленный обратный вызов всякий раз, когда срабатывает уведомитель. Это используется для выполнения одноразовых задач, таких как навигация, когда меняется уведомитель.

Кажется, все работает нормально, но я случайно наткнулся на документацию didUpdateWidget, которая гласит:

Если метод построения State зависит от объекта, который может сам изменять состояние, например ChangeNotifier или Stream, или какого-либо другого объекта, на который можно подписаться для получения уведомлений, тогда обязательно подпишитесь и правильно отписаться в initState, didUpdateWidget и утилизировать:

  • В initState подписаться на объект.
  • В didUpdateWidget отписаться от старого объекта и подписаться на новый, если обновленный виджет Конфигурация требует замены объекта.
  • При утилизации отписаться от объекта.

Я обращаюсь к первому и последнему пункту по очевидным причинам, но может кто-нибудь потерять свет, почему я также должен реализовать didUpdateWidget? Что может go ошибиться, если я этого не сделаю?

Бонусный вопрос: я еще не использую провайдера в своем приложении. Предлагает ли что-то подобное уже из коробки? Я не смог найти что-то подобное.

Код моего виджета:

class ChangeNotifierListener<T extends ChangeNotifier> extends StatefulWidget {
  final Widget child;
  final T changeNotifier;
  final void Function(T changeNotifier) onChanged;

  ChangeNotifierListener(
      {@required this.child,
      @required this.changeNotifier,
      @required this.onChanged});

  @override
  _ChangeNotifierListenerState createState() =>
      _ChangeNotifierListenerState<T>();
}

class _ChangeNotifierListenerState<T extends ChangeNotifier>
    extends State<ChangeNotifierListener<T>> {
  VoidCallback _callback;

  @override
  Widget build(BuildContext context) => widget.child;

  @override
  void initState() {
    super.initState();
    _callback = () {
      widget.onChanged(widget.changeNotifier);
    };
    widget.changeNotifier.addListener(_callback);
  }

  @override
  void dispose() {
    widget.changeNotifier.removeListener(_callback);
    super.dispose();
  }
}

1 Ответ

1 голос
/ 23 марта 2020

Эта часть документации о том, как возможно, чтобы ваш виджет перестраивался с другими параметрами.

Например, с StreamBuilder первая сборка может быть похожа на:

StreamBuilder(
  stream: Stream.value(42),
  builder: ...
)

А затем что-то меняется, и StreamBuilder перестраивается с помощью:

StreamBuilder(
  stream: Stream.value(21),
  builder: ...
)

В этом случае stream изменяется. Поэтому StreamBuilder необходимо прекратить прослушивание предыдущего Stream и прослушивание нового.

Это будет сделано, хотя следующее didUpdateWidget:

StreamSubscription<T> subscription;

@override
void didUpdateWidget(StreamBuilder<T> oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (widget.stream != oldWidget.stream) {
    subscription?.cancel();
    subscription = widget.stream?.listen(...);
  }
}

То же самое logi c относится к ChangeNotifier и любому другому наблюдаемому объекту.

...