Хроники управления состоянием Flutter 7.

Если бы вы каким-то образом прошли через него и имели некоторое представление о пакете Provider, вы бы поняли, насколько он хорош в решении проблемы, в которой он нуждается. Как обсуждалось в моей предыдущей статье, провайдеры построены на основе класса Inherited Widget, поэтому он легко использует преимущества использования InheritedWidgets, но при этом решает большинство проблем или трудностей, которые часто возникают при использовании класса InheritedWidget. Вопросы вроде.

  • Наличие слишком большого количества шаблонного кода (громоздкого и сложного в обслуживании)
  • Слишком много вложенного кода, что затрудняет факторизацию унаследованных виджетов и может сбивать с толку.
  • Вложенный ад, когда у нас есть несколько InheritedWidgets, которые мы хотим использовать, или обернуть один виджет.

В предыдущей статье мы увидели, как, используя только класс Provider и простой класс модели, мы смогли сделать доступным класс модели для виджетов с очень минимальным кодом. Но это не единственная причина, по которой мы решили использовать пакет Provider, мы хотим иметь возможность предоставлять значения, которые при изменении нашего пользовательского интерфейса должны отражать эти изменения.

Как же тогда мы можем изменить значения в нашей модели, чтобы изменения отражались в зависимых виджетах?

У нас есть ChangeNotifiers.

«Класс, который может быть расширен или смешан, в котором предоставляется API уведомления об изменениях с использованием VoidCallBack для уведомления».

Вся концепция changeNotifiers, которая делает это возможным, заключается в том, что мы можем создать класс модели, который можно прослушивать, так что при изменении он излучает какой-то сигнал. Провайдер также может подписываться на изменения и прислушиваться к ним, так что когда класс модели внутренне изменяется и излучает сигнал, он должен предоставлять новые значения всем виджетам в зависимости от этого.

По сути, чтобы сделать наш класс модели Listenable, мы наследуем (или используем смешивание) от класса ChangeNotifier. Эти классы ChangeNotifier внутренне являются подклассами класса Listenable, иронично, правда? Чтобы сделать наш класс модели Listenable, нам нужно расширить Listenable.

Наследование Listenable, например ChangeNotifier, дает нам доступ к методу notifyListeners (это тот VoidCallBack), который предназначен только для уведомления или выдачи сигналов при внесении изменений.

Как видно, слушатель похож по функциям на функцию setState в том, что он уведомляет соответствующий класс прослушивания или виджет о некоторых неизбежных изменениях, и может быть выполнено правильное действие (перестройка).

Теперь вместо класса Provider мы подписываемся на эту модель с помощью ChangeNotifierProvider. Разница между ChangeNotifierProvider и Provider заключается в том, что: Provider принимает значение и предоставляет его всем виджетам, но не отслеживает изменения этого значения.

По сути, это некая форма глобальной переменной для виджетов?

Да, по сути, поставщик действует как своего рода глобальная переменная для виджетов и используется как таковая (иногда просто для кеширования значений и использования их при необходимости), разница с типичными глобальными переменными заключается в том, что вместо предоставления глобального доступа к value, он предоставляет ограниченный доступ этого значения к определенному поддереву виджетов, это предотвращает тесную связь, которая идет с глобальными переменными, а также решает проблемы с внедрением конструктора. Вы можете ознакомиться с этой статьей, если хотите узнать немного больше.

Вернуться туда, где мы были.

Разница между ChangeNotifierProvider и Provider. Так что да, провайдеры не просто уведомляют об изменениях в двух словах. Однако ChangeNotifierProvider - это спецификация типа поставщика для прослушиваемых объектов (моделей), который затем будет прослушивать модель и сообщать зависимым от нее виджетам, что нужно перестроить, если значение модели изменится.

ListenableProvider: конкретный поставщик для объекта Listenable. ListenableProvider будет прослушивать объект и запрашивать зависимые от него виджеты при каждом вызове прослушивателя.

ChangeNotifierProvider: спецификация ListenableProvider для ChangeNotifier. При необходимости он автоматически вызовет ChangeNotifier.dispose.

Как мы видим, он предоставляется так же, как и обычный провайдер, фактически он также потребляется таким же образом.

Как видно выше, мы потребляем значения почти одинаково, но есть некоторая разница в том, что есть аргумент «listen: false» в вызове Provider.of () в onTap.

Но почему?

Это связано с тем, что по умолчанию при вызове Provider.of () без указания мы слушаем изменения, но flutter не позволяет прослушивать изменения, когда мы вызываем Provider.of () вне метода сборки, это потому, что в flutter собственными словами: «Он не поддерживается, потому что может бессмысленно перестроить виджет, связанный с обработчиком событий, когда дерево виджетов не заботится о значении». что имеет смысл, потому что мы не хотим, чтобы пользовательский интерфейс перестраивался (при изменении значения), потому что внешний метод, не имеющий ничего общего с пользовательским интерфейсом, использует значение, которое не используется при создании пользовательского интерфейса.

Для большей ясности

Как уже говорилось, различные решения по управлению состоянием возникают из-за необходимости поддерживать разработчиками надлежащие методы разработки.

Глядя на наш модельный класс, хотя что-то простое по-прежнему поражает нас, разве классы не должны быть неизменными?

Почему тогда наш класс модели изменчив, это какое-то исключение или что-то не так?

На самом деле, ChangeNotifiers не лишен своих недостатков, и поскольку в тривиальных случаях изменчивость классов может быть приемлемой, мы, как «Хорошие программисты, ха-ха», хотели бы поддерживать практику неизменности классов. Но если мы добавим поля final в наш класс модели, то изменение (обновление) их, как показано выше, больше не будет возможным, и нам нужно будет выполнить некоторые виды гимнастики, чтобы это сделать. Даже когда мы занимаемся гимнастикой, мы не сможем идеально справиться с изменениями, и они начинают превращаться в шаблонный код.

Во-вторых, у нас есть проблемы, когда, если у нас есть более одного поля в нашем классе модели, обновление одного из полей будет напрямую означать перестройку любого виджета, потребляющего этот класс, независимо от конкретного значения, которое он потребляет. Хотя провайдеры предоставляют новый способ конкретизировать значение, изменение которого должно запускать перестройку (в методе расширения select; мы увидим больше об этом в будущих заметках), это новая сложность и сценарий, который нам нужно обрабатывать каждый раз. время мы потребляем информацию, но, конечно, мы не всегда можем быть уверены, когда это может быть необходимо или нет.

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

Чтобы узнать больше о Flutter, подпишитесь на сообщество Flutter в Twitter: https://twitter.com/FlutterComm