【问题标题】:Flutter Provider: How to notify a model that a change happened on a model it contains?Flutter Provider:如何通知模型它包含的模型发生了变化?
【发布时间】:2020-08-01 12:26:39
【问题描述】:

我开始通过使用 Provider 构建一个简单的 Todo 应用程序来学习 Flutter/Dart,但我遇到了一个状态管理问题。需要明确的是,我编写的代码有效,但似乎......错了。我找不到任何与我的案例相似的示例,足以让我理解解决问题的正确方法是什么。

This is what the app looks like

这是一个按部分(“冷冻”、“水果和蔬菜”)划分的杂货清单。每个部分都有多个项目,并显示“已完成 x of y”进度指示器。每一个item在被按下时都会“完成”。

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();
        })
    );
  }
}

我想要的下一步是在一个 section 中包含多个 items,它会根据完成的项目数来跟踪完整性。

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()
              )
          );
        }
      )
    );
  }
}

问题:

  1. 在两个小部件中都有ChangeNotifierProviderConsumer 似乎很奇怪。我见过的例子都没有做到这一点。
  2. GroceryListSectionModel 监听所有GroceryItemModels 上的更改以将更改传播回树上是绝对错误的。我不知道如何正确扩展。

有什么建议吗?谢谢!

【问题讨论】:

    标签: flutter dart state-management flutter-provider


    【解决方案1】:

    这不是嵌套提供程序,但我认为在您的示例中这是更好的方法..

    每个 section ("Frozen", "Fruits and Veggies") 只定义一个 ChangeNotifierProvider

    ItemModel 中的 complete() 函数位于 GroceryListSectionModel() 中,并带有来自当前列表索引的参数

    class GroceryListSection extends StatelessWidget {
      final GroceryListSectionModel model;
     // final ValueChanged<bool> onChanged;
    
      GroceryListSection(this.model);
    
      @override
      Widget build(BuildContext context) {
    
        return new ChangeNotifierProvider<GroceryListSectionModel>(
            create: (context) => GroceryListSectionModel(model.name, model.items),
            child: new 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.asMap().map((i, groceryItemModel) => MapEntry(i, GroceryItem(groceryItemModel, i))).values.toList()
                  )
              );
            }
          )
        );
      }
    }
    
    class GroceryItem extends StatelessWidget {
      final GroceryItemModel model;
      final int index;
    
      GroceryItem(this.model, this.index);
    
      @override
      Widget build(BuildContext context) {
        return ListTile(
          title: Text(model.name),
          leading: model.completed ? Icon(Icons.check_circle, color: Colors.green) : Icon(Icons.radio_button_unchecked),
          onTap: () => Provider.of<GroceryListSectionModel>(context, listen: false).complete(index),
        );
    
      }
    }
    
    class GroceryListSectionModel extends ChangeNotifier {
      String name;
      List<GroceryItemModel> items;
    
      GroceryListSectionModel(this.name, [items]) {
        this.items = items == null ? [] : items;
      }
    
      int itemCount() => items.length;
      int completedItemCount() => items.where((item) => item.completed).length;
    
      // complete Void with index from List items
      void complete(int index) {
        this.items[index].completed = true;
        notifyListeners();
      }
    
    }
    
    // normal Model without ChangeNotifier
    class GroceryItemModel {
      final String name;
      bool completed = false;
    
      GroceryItemModel({this.name, completed}) {
        this.completed = completed == null ? false : completed;
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-31
      • 2018-04-11
      • 2012-04-13
      • 2011-09-13
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多