Provider: Consumer
Часть раздела Управление состоянием путешествия по Flutter на Coddy. Урок 12 из 27.
Здесь провайдер создаётся внутри собственного build у MyApp, а тот же build сразу под ним запрашивает лампу. Приложение выдаёт ошибку: context принадлежит MyApp, который находится выше провайдера, а виджет может найти только провайдеры, расположенные выше него.
Это исправляет Consumer. Это виджет, поэтому он находится ниже провайдера, а его builder получает новый context и саму модель:
Consumer<Lamp>(
builder: (context, lamp, child) {
return Text(lamp.isOn ? 'On' : 'Off');
},
)Функция builder запускается снова каждый раз, когда лампа вызывает notifyListeners(), подобно виджету, который за ней следит. Внутри неё можно напрямую вызывать методы модели у lamp: onPressed: () => lamp.toggle().
Consumer также перестраивает только обёрнутую им часть, поэтому, если обернуть изменяющуюся часть, остальная часть экрана останется без изменений. В большинстве приложений вы будете использовать context.watch в отдельном виджете, а к Consumer обращаться, когда находитесь в том же build, что и провайдер.
Задание
СреднеПриложение открывается с ошибкой. Помести части лампы внутрь Consumer:
- Оберни
ColumnвConsumer<Lamp>и верниColumnиз его builder. - Внутри используй
lampиз builder для значка, текста и кнопки.
Попробуйте сами
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Lamp extends ChangeNotifier {
bool _isOn = false;
bool get isOn => _isOn;
void toggle() {
_isOn = !_isOn;
notifyListeners();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => Lamp(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: const Text('Lamp')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
context.watch<Lamp>().isOn ? Icons.lightbulb : Icons.lightbulb_outline,
size: 96,
color: context.watch<Lamp>().isOn ? Colors.amber : Colors.grey,
),
Text(context.watch<Lamp>().isOn ? 'The lamp is on' : 'The lamp is off'),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => context.read<Lamp>().toggle(),
child: const Text('Switch'),
),
],
),
),
),
),
);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Управление состоянием
Потренируйтесь самостоятельно: Онлайн-компилятор Flutter