К содержимому

Провайдеры

Теперь, когда мы установили Riverpod, давайте поговорим о провайдерах.

Провайдеры - самая важная составляющая Riverpod приложения. Провайдер - объект, который инкапсулирует часть состояния и позволяет наблюдать за этим состоянием.

Зачем использовать провайдеры?

Инкапсуляция части состояния в провайдере:

  • Предоставляет легкий доступ к этому состоянию из разных мест. Провайдеры являются полной заменой таким паттернам, как Singleton, Service Locator, Dependency Injection и InheritedWidget.

  • Упрощает совместное использование данного состояния с другими. Пытались когда-нибудь объединить несколько объектов в один? Данный сценарий реализован внутри провайдеров.

  • Повышение производительности. Отслеживание перестроек виджетов или кэширование результатов затратных вычислений. Провайдеры гарантируют, что только изменение состояния вызывает перестойку/перевычисление.

  • Повышение тестируемости вашего приложения. С провайдерами вам больше не нужны setUp/tearDown. Более того, можно изменить поведение любого провайдера во время теста, что позволяет легко протестировать конкретное поведение.

  • Простое внедрение дополнительное функционала, как логгирование или pull-to-refresh.

Создание провайдера

Существует множество различных провайдеров, но все они работают одинаково.

Самый распространенный вариант использования это объявление провайдера в виде глобальной константы:

final myProvider = Provider((ref) {
return MyValue();
});
примечание

Не переживайте, что провайдеры создаются как глобальные переменные. Провайдеры полностью неизменяемы. Объявление провайдера ничем не отличается от объявления функции. Провайдеры поддаются тестированию и сопровождению.

Данный отрывок кода состоит из трех частей:

  • final myProvider - объявление переменной. В дальнейшем мы будем использовать ее для чтения состояния нашего провайдера. Провайдеры всегда должны быть объявлены с final.

  • Provider - тип провайдера, который мы решили использовать. Provider самый простой провайдер. Он предоставляет объект, который никогда не изменится. Мы можем заменить Provider другим провайдером, например StreamProvider или StateNotifierProvider, для иного взаимодействия со значением.

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

Тип возвращаемого значения данной функции определяется типом провайдера, который мы используем. Например, для Provider функция может создавать объект любого типа. Однако для StreamProvider функция должна возвращать Stream.

к сведению

Вы можете объявить сколько угодно провайдеров без ограничения. Riverpod, в отличие от package:provider, позволяет создавать несколько провайдеров, хранящих один и тот же тип:

final cityProvider = Provider((ref) => 'London');
final countryProvider = Provider((ref) => 'England');

Два провайдера со значением типа String не вызовут ошибку.

предупреждение

Для работы с провайдерами мы должны добавить ProviderScope в корень вашего Flutter приложения:

void main() {
runApp(ProviderScope(child: MyApp()));
}

Разнообразие провайдеров

Существует множество разных провайдеров для различных случаев применения.

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

Тип ПровайдераФункция создания провайдераПример использования
ProviderВозвращает любой типКласс сервиса / вычисленное значение (отфильтрованный список)
StateProviderВозвращает любой типУсловие фильтрации / простейший объект состояния
FutureProviderВозвращает Future любого типаРезультат обращения к API
StreamProviderВозвращает Stream любого типаStream результатов, полученных с API
StateNotifierProviderВозвращает подкласс StateNotifierСложный объект состояния, который можно изменить только через интерфейс
ChangeNotifierProviderВозвращает подкласс ChangeNotifierСложный объект состояния, который можно изменить напрямую
предупреждение

Не смотря на то что каждый провайдер имеет свое предназначение, ChangeNotifierProvider не рекомендуется использовать в масштабируемых приложениях из-за проблем с изменяемым состоянием. Этот провайдер есть в пакете flutter_riverpod для легкой миграции с package:provider, также он необходим для специфичных случаев, таких как взаимодействие с пакетами Navigator 2.

Модификаторы провайдера

Все провайдеры имеют встроенную возможность расширения функционала.

Можно добавить новые свойства к объекту ref или же слегка изменить чтение провайдера. Модификаторы можно использовать с любым провайдером. Синтаксис их использования похож на именованный конструктор:

final myAutoDisposeProvider = StateProvider.autoDispose<int>((ref) => 0);
final myFamilyProvider = Provider.family<String, int>((ref, id) => '$id');

На данный момент существует лишь два модификатора:

  • .autoDispose, который автоматически аннулирует состояние провайдера, если он больше никем не прослушивается.
  • .family, который позволяет создать провайдер с использованием дополнительных параметров.
примечание

Можно применить сразу несколько модификаторов к одному провайдеру:

final userProvider = FutureProvider.autoDispose.family<User, int>((ref, userId) async {
return fetchUser(userId);
});

На этом заканчивается данный гайд!

Также вы можете изучить Как читать провайдер. Посмотрите еще Как комбинировать провайдеры.