Flutter 颤振提供者:如何通知模型它包含的模型发生了更改?

Flutter 颤振提供者:如何通知模型它包含的模型发生了更改?,flutter,dart,state-management,flutter-provider,Flutter,Dart,State Management,Flutter Provider,我开始通过使用Provider构建一个简单的Todo应用程序来学习flatter/Dart,我遇到了一个状态管理问题。很明显,我写的代码很有效,但似乎。。。错。我找不到任何与我的案例足够相似的例子来理解解决问题的正确方法 这是一份按部分划分的杂货清单(“冷冻”、“水果和蔬菜”)。每个部分都有多个项目,并显示“x/y完成”进度指示器。按下时,每个项目都“完成” GroceryItemModel如下所示: class GroceryItemModel extends ChangeNotifier

我开始通过使用Provider构建一个简单的Todo应用程序来学习flatter/Dart,我遇到了一个状态管理问题。很明显,我写的代码很有效,但似乎。。。错。我找不到任何与我的案例足够相似的例子来理解解决问题的正确方法

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

GroceryItemModel
如下所示:

class GroceryItemModel extends ChangeNotifier {
  final String name;

  bool _completed = false;

  GroceryItemModel(this.name);

  bool get completed => _completed;

  void complete() {
    _completed = true;
    notifyListeners();
  }
}
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;
}
我在
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();
        })
    );
  }
}
我在
杂货店列表部分
小部件中使用它,如下所示:

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()
              )
          );
        }
      )
    );
  }
}
class GroceryListSection扩展了无状态小部件{
最终杂货店模型;
变更后的最终价值;
GroceryListSection(this.model,this.onChanged);
@凌驾
小部件构建(构建上下文){
返回ChangeNotifierProvider.value(
价值:模型,
儿童:消费者(
生成器:(上下文、杂货店列表部分、子项){
返回容器(
子文件:扩展文件(
标题:文本(型号名称),
字幕:文本(${groceryListSection.itemCount()}的${groceryListSection.completedItemCount()}已完成”),
子项:groceryListSection.items.map((groceryItemModel)=>
GroceryItem(groceryItemModel)).toList()
)
);
}
)
);
}
}
问题:

  • 在这两个小部件中都有
    ChangeNotifierProvider
    Consumer
    ,这似乎很奇怪。我所看到的例子中没有一个是这样的
  • GroceryListSectionModel
    侦听所有
    GroceryItemModels
    上的更改,以便将更改传播回树,这绝对是错误的。我看不出它是如何正确扩展的

  • 有什么建议吗?谢谢

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

    每个
    部分(“冷冻”、“水果和蔬菜”)只定义一个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;
      }
    
    }
    
    class GroceryListSection扩展了无状态小部件{
    最终杂货店模型;
    //变更后的最终价值;
    杂货店营业部(this.model);
    @凌驾
    小部件构建(构建上下文){
    返回新的ChangeNotifierProvider(
    create:(context)=>GroceryListSectionModel(model.name,model.items),
    儿童:新消费者(
    生成器:(上下文、杂货店列表部分、子项){
    返回容器(
    子文件:扩展文件(
    标题:文本(型号名称),
    字幕:文本(${groceryListSection.itemCount()}的${groceryListSection.completedItemCount()}已完成”),
    子项:groceryListSection.items.asMap().map((i,groceryItemModel)=>MapEntry(i,GroceryItem(groceryItemModel,i))).values.toList()
    )
    );
    }
    )
    );
    }
    }
    类GroceryItem扩展了无状态小部件{
    最终杂货店模型;
    最终整数指数;
    GroceryItem(this.model,this.index);
    @凌驾
    小部件构建(构建上下文){
    返回列表块(
    标题:文本(型号名称),
    前导:model.completed?图标(Icons.check_circle,颜色:Colors.green):图标(Icons.radio_button_unchecked),
    onTap:()=>Provider.of(上下文,侦听:false)。完成(索引),
    );
    }
    }
    类GroceryListSectionModel扩展了ChangeNotifier{
    字符串名;
    清单项目;
    GroceryListSectionModel(this.name,[items]){
    this.items=items==null?[]:items;
    }
    int itemCount()=>items.length;
    int completedItemCount()=>items.where((item)=>item.completed).length;
    //使用列表项的索引完成Void
    无效完成(整数索引){
    此.items[index].completed=true;
    notifyListeners();
    }
    }
    //不带ChangeNotifier的正常模型
    类GroceryItem模型{
    最后的字符串名;
    bool completed=false;
    GroceryItemModel({this.name,completed}){
    this.completed=completed==null?false:已完成;
    }
    }