Как что-то сделать, если ChangeNotifier уведомляет с помощью пакета провайдера (аналогично BlocListener)?

Чего я хочу

У меня простая модель. Модель простирается от ChangeNotifier. Если ChangeNotifier вызывает notifyListeners(), я хочу «сделать» что-то вроде показа SnackBar или Dialog. Я предоставляю модель с пакетом Provider для своего дерева виджетов.

С чем это можно сравнить?

Раньше я использовал пакет flutter_bloc. Этот пакет предлагает BlocListener. С BlocListener я могу что-то «делать» при изменении состояния. Пример кода:

BlocListener<BlocA, BlocAState>(
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  child: Container(),
)

В приведенном выше примере дочерний элемент не будет перестраиваться, но я все еще могу что-то делать в зависимости от состояния.

Есть ли что-нибудь сопоставимое с пакетом провайдера? Я читал в документации пакета, что ListenableProvider даст больше свободы для таких вещей, как «анимация». Но я не знаю, могу ли я каким-то образом использовать этого провайдера, чтобы показывать закусочную в уведомлении.

Изменить: я спросил Реми, автора Provider, в Twitter. С небольшим количеством символов он сказал мне, что я могу использовать didChangeDependencies для этого поведения.


person Sonius    schedule 18.12.2019    source источник


Ответы (1)


Будьте осторожны при использовании didChangeDependencies для этого. didChangeDepdnencies можно использовать для этого только в нескольких случаях, и https://github.com/flutter/flutter/pull/49527 сделает невозможным даже в них.

Основная проблема в том, что didChangeDepdnencies иногда (или всегда после # 49527) вызывается в точке, где дерево заблокировано от изменений состояния. Перед запросом на вытягивание это безопасно только для вызовов, которые:

  • Не в первый раз (вызывается из области сборки)
  • Это не время, когда элемент деактивируется и, в конечном итоге, размонтируется, поэтому он больше не находится в допустимом месте в дереве (этот вызов больше не будет происходить вообще после запроса на вытягивание).

Более безопасный способ сделать это:

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  if (Provider.of(context).whatever == someCondition) {
    SchedulerBinding.instance.addPostFrameCallback(() {
      // show modal or dialog
    });
  }
}

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

Вероятно, есть более элегантные решения, чем это (например, добавление обратного вызова непосредственно в notifyListeners для вашего ChangeNotifier, при условии, что он срабатывает только тогда, когда дерево находится в изменяемом состоянии).

person Dan Field    schedule 28.01.2020