Код-ревью Middle Управление состоянием обновлено
Код-ревью: Provider и перестроения
Вопрос
Экран корзины на Provider. Найдите ошибки подписок и логики.
class Cart extends ChangeNotifier {
final List<Item> items = [];
void add(Item i) {
items.add(i);
}
int get total => items.fold(0, (s, i) => s + i.price);
}
class CartScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final cart = context.read<Cart>();
return Column(children: [
Text('Итого: ${cart.total}'),
ElevatedButton(
onPressed: () => context.watch<Cart>().add(Item.sample()),
child: const Text('Добавить'),
),
const BigBanner(),
]);
}
}
Коротко
Правило Provider: watch/select в build, read в колбэках. Изменение состояния в ChangeNotifier всегда заканчивается notifyListeners().
Что должен найти ревьюер
- Ошибкастрока 4После изменения нет
notifyListeners(): подписчики не узнают о новом товаре. - Стильстрока 2Список отдаётся наружу изменяемым: любой может сделать
cart.items.addв обход уведомлений. ОтдаватьList.unmodifiableили копию. - Ошибкастрока 12
readвbuildне подписывает виджет: итог не обновится. Нуженwatchилиselect((Cart c) => c.total). - Ошибкастрока 16
watchв обработчике нажатия запрещён (ассерт в debug) и бессмыслен: нуженread. - Производительностьстрока 6
totalпересчитывается на каждом обращении. Для больших корзин держать сумму в поле и обновлять вadd.
Разбор
Правило Provider: watch/select в build, read в колбэках. Изменение состояния в ChangeNotifier всегда заканчивается notifyListeners(). Внутренние коллекции не отдаются наружу изменяемыми. Точечный select по total перестраивает только текст.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.