Provider: делимся моделью
Часть раздела Управление состоянием путешествия по Flutter на Coddy. Урок 9 из 27.
Поднятие состояния вверх работает, пока виджеты находятся рядом. Когда значение нужно по всему приложению — на двух экранах, в верхней панели, глубоко внутри списка, — его пришлось бы передавать через каждый промежуточный виджет. Provider позволяет этого избежать. Это пакет: набор кода, который вы подключаете с помощью import 'package:provider/provider.dart';.
Он состоит из трёх частей. Во-первых, модель: класс, который хранит данные и extends ChangeNotifier. Его методы изменяют данные, а затем вызывают notifyListeners():
class CupCounter extends ChangeNotifier {
int _cups = 0;
int get cups => _cups;
void addCup() {
_cups++;
notifyListeners();
}
}Во-вторых, ChangeNotifierProvider высоко в дереве один раз создаёт модель и передаёт её каждому виджету ниже:
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CupCounter(),
child: const MyApp(),
),
);
}В-третьих, любой виджет ниже запрашивает её: context.watch<CupCounter>(), чтобы отобразить её, context.read<CupCounter>(), чтобы вызвать метод. Заголовок и кнопка ниже получают один и тот же счётчик, и ни одному из них ничего не передаётся.
Задание
СреднеОткрой приложение: появится ошибка, потому что заголовок запрашивает CupCounter, а выше его никто не предоставляет.
- В
mainоберниMyAppвChangeNotifierProvider, который создаётCupCounter.
Попробуйте сами
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CupCounter extends ChangeNotifier {
int _cups = 0;
int get cups => _cups;
void addCup() {
_cups++;
notifyListeners();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const CupsTitle()),
body: const Center(child: AddCupButton()),
);
}
}
class CupsTitle extends StatelessWidget {
const CupsTitle({super.key});
@override
Widget build(BuildContext context) {
final counter = context.watch<CupCounter>();
return Text('Cups: ${counter.cups}');
}
}
class AddCupButton extends StatelessWidget {
const AddCupButton({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
context.read<CupCounter>().addCup();
},
child: const Text('Another cup'),
);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Управление состоянием
Потренируйтесь самостоятельно: Онлайн-компилятор Flutter