Код-ревью 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().

Что должен найти ревьюер

  1. Ошибкастрока 4
    После изменения нет notifyListeners(): подписчики не узнают о новом товаре.
  2. Стильстрока 2
    Список отдаётся наружу изменяемым: любой может сделать cart.items.add в обход уведомлений. Отдавать List.unmodifiable или копию.
  3. Ошибкастрока 12
    read в build не подписывает виджет: итог не обновится. Нужен watch или select((Cart c) => c.total).
  4. Ошибкастрока 16
    watch в обработчике нажатия запрещён (ассерт в debug) и бессмыслен: нужен read.
  5. Производительностьстрока 6
    total пересчитывается на каждом обращении. Для больших корзин держать сумму в поле и обновлять в add.

Разбор

Правило Provider: watch/select в build, read в колбэках. Изменение состояния в ChangeNotifier всегда заканчивается notifyListeners(). Внутренние коллекции не отдаются наружу изменяемыми. Точечный select по total перестраивает только текст.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме