Provider: watch или read
Часть раздела Управление состоянием путешествия по Flutter на Coddy. Урок 11 из 27.
Получить модель из Provider можно двумя способами, и они выполняют разные задачи.
context.watch<StepCounter>() получает модель и подписывается на неё: когда модель вызывает notifyListeners(), этот виджет строится заново. Используй его в build для всего, что отображается на экране.
context.read<StepCounter>() получает модель один раз, без подписки. Используй его в обратных вызовах, таких как onPressed, когда нужно вызвать метод, а не отображать что-либо:
Widget build(BuildContext context) {
final steps = context.watch<StepCounter>().steps; // отображает
return ElevatedButton(
onPressed: () => context.read<StepCounter>().walk(), // действует
child: Text('$steps steps'),
);
}Перепутаешь их — и сразу заметишь. read в build будет вечно показывать первое значение. watch внутри onPressed вызовет ошибку, потому что нажатие — это не построение виджета, и подписываться не на что.
Задание
ЛегкоWalk добавляет 1000 шагов к модели, но на экране по-прежнему отображается 0 steps.
- Сделай так, чтобы строка с количеством шагов обновлялась в соответствии с моделью и при каждом нажатии показывала новое число.
- Оставь вызов кнопки без изменений.
Попробуйте сами
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class StepCounter extends ChangeNotifier {
int _steps = 0;
int get steps => _steps;
void walk() {
_steps += 1000;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => StepCounter(),
child: 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) {
final steps = context.read<StepCounter>().steps;
return Scaffold(
appBar: AppBar(title: const Text('Steps')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('$steps steps', style: const TextStyle(fontSize: 40)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
context.read<StepCounter>().walk();
},
child: const Text('Walk'),
),
],
),
),
);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Управление состоянием
Потренируйтесь самостоятельно: Онлайн-компилятор Flutter