В предыдущем посте мы вспомнили, что такое InheritedWidget. Сегодня продолжаю отвечать на вопрос нашего подписчика о том, что такое Provider и как он работает.
Библиотека provider — одна из наиболее известных во Flutter-сообществе. Она дает доступ к специальному виджету Provider и его вариациям, которые сами разработчики пакета позиционируют как более удобную версию InheritedWidget:
A wrapper around InheritedWidget to make them easier to use and more reusable.
Здесь важно понять, что Provider работает по тому же принципу, что и InheritedWidget — данные прокидываются по дереву виджетов, а доступ к ним в любой момент можно получить по контексту.
Передача данных
Provider позволяет удобно передавать данные дальше по дереву виджетов. Как и InheritedWidget, его необходимо встраивать в дерево выше тех мест, которые будут использовать передаваемые данные.
Реализовать это можно двумя способами.
1. С помощью стандартного конструктора
Provider()Здесь создание источника данных выполняется через функцию create.
Provider(
create: (context) => CustomData(),
child: Container(),
),
2. С помощью конструктора
Provider.value()Этот конструктор не будет создавать новый экземпляр источника данных — он требует передачу уже ранее созданного.
final customData = CustomData();
...
Provider.value(
value: customData,
child: Container(),
),
При необходимости провайдить несколько источников данных можно использовать MultiProvider.
Кроме этого библиотека дает доступ к множеству разных видов провайдера, например, StreamProvider и FutureProvider.
Чтение данных
Далее по дереву от экземпляра провайдера мы можем получить переданные данные через контекст. Для этого существует три метода:
1.
context.read<T>() — однократно считывает данные 2.
context.watch<T>() — прослушивает данные, при их изменении обновляет текущий виджет3.
context.select<T, R>(R cb(T value)) — прослушивает только указанную часть данных, например, одно полеБиблиотека также дает доступ к виджетам Consumer и Selector. Они так же, как методы
context.watch и context.select,прослушивают изменения данных провайдера, но позволяют ребилдить не весь текущий виджет, а только дочерние.
class Example extends StatelessWidget {
const Example({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('Строка 1'),
Text(context.watch<CustomData>().data), // заставит перестроиться весь виджет Example
const Text('Строка 3'),
],
);
}
}
class Example2 extends StatelessWidget {
const Example2({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('Строка 1'),
Consumer<CustomData>( // перестроит только дочерний Text
builder: (context, customData, _) {
return Text(customData.data);
},
),
const Text('Строка 3'),
],
);
}
}
Еще больше полезной информации можно найти в документации классов библиотеки, а также в README.
