Я начинаю изучать Flutter / Dart, создав простое приложение Todo с использованием Provider, и столкнулся с проблемой управления состоянием. Чтобы было ясно, код, который я написал, работает, но кажется ... неправильным. Я не могу найти примеров, которые бы напоминали мой случай, чтобы я мог понять, как правильно подойти к проблеме.
Так выглядит приложение
Это список покупок, разделенный на разделы («Замороженные», «Фрукты и овощи»). Каждый раздел имеет несколько элементов и отображает индикатор хода выполнения "x of y complete". Каждый элемент «завершается» при нажатии.
GroceryItemModel
выглядит следующим образом:
class GroceryItemModel extends ChangeNotifier {
final String name;
bool _completed = false;
GroceryItemModel(this.name);
bool get completed => _completed;
void complete() {
_completed = true;
notifyListeners();
}
}
И я использую его в виджете GroceryItem
как Итак:
class GroceryItem extends StatelessWidget {
final GroceryItemModel model;
GroceryItem(this.model);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: model,
child: Consumer<GroceryItemModel>(builder: (context, groceryItem, child) {
return ListTile(
title: Text(groceryItem.name),
leading: groceryItem.completed ? Icon(Icons.check_circle, color: Colors.green) : Icon(Icons.radio_button_unchecked)
onTap: () => groceryItem.complete();
})
);
}
}
Следующий шаг, который я хочу, - включить несколько элементов в секцию , которая отслеживает полноту на основе количества выполненных элементов.
GroceryListSectionModel
выглядит так:
class GroceryListSectionModel extends ChangeNotifier {
final String name;
List<GroceryItemModel> items;
GroceryListSectionModel(this.name, [items]) {
this.items = items == null ? [] : items;
// THIS RIGHT HERE IS WHERE IT GETS WEIRD
items.forEach((item) {
item.addListener(notifyListeners);
});
// END WEIRD
}
int itemCount() => items.length;
int completedItemCount() => items.where((item) => item.completed).length;
}
И я использую его в виджете GroceryListSection
примерно так:
class GroceryListSection extends StatelessWidget {
final GroceryListSectionModel model;
final ValueChanged<bool> onChanged;
GroceryListSection(this.model, this.onChanged);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: model,
child: Consumer<GroceryListSectionModel>(
builder: (context, groceryListSection, child) {
return Container(
child: ExpansionTile(
title: Text(model.name),
subtitle: Text("${groceryListSection.completedItemCount()} of ${groceryListSection.itemCount()} completed"),
children: groceryListSection.items.map((groceryItemModel) =>
GroceryItem(groceryItemModel)).toList()
)
);
}
)
);
}
}
Проблемы:
- Кажется странным иметь
ChangeNotifierProvider
и Consumer
в обоих виджетах. Ни один из примеров, которые я видел, не делает этого. - Это определенно неправильно, если
GroceryListSectionModel
слушает изменения на всех GroceryItemModels
, чтобы изменения распространялись обратно вверх по дереву. Я не вижу, как это может масштабироваться правильно.
Есть предложения? Спасибо!