【问题标题】:List is emptied after notifyListeners在 notifyListeners 后列表被清空
【发布时间】:2022-01-20 00:46:11
【问题描述】:

我有一个奇怪的,我一直在挠头

我有一个使用提供程序的类的属性 除了这种特殊情况,我可以正常访问和修改:

我将产品添加到 _products 列表中

_products.add(product);
notifyListeners();

此时产品是一个具有以下属性的类

name String;
id String;
ingredients List<String>;

比如说产品是

final product = Product(name:'milk', id:1, ingredients:['milk']);

这个元素被添加到列表中,我可以在调试中看到现在 _products 确实是一个列表,里面有 1 个项目并且所有属性都是正确的

一旦它通知听众他们获得了 _products 的新值,我可以看到他们收到了新值就好了,只是由于某种奇怪的原因,成分列表是空的!

[ Product(name:'milk', id:1, ingredients:[]) ] // _products for representation purposes

我刚刚在通知之前验证了 _products 的值,它具有正确的成分属性,然后在通知之后,该属性变成了一个空列表 其他 2 个属性 id 和 name 已正确更新

我已经非常彻底地检查了,我没有代码可以修改 _products else where

【问题讨论】:

    标签: flutter dart flutter-provider


    【解决方案1】:

    由于我们不知道您对 Product 和 ProductList 的实现细节,我自己在这种情况下创建了一个示例。

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    
    class Product
    {
      final String name;
      final String id;
      final List<String> ingredients;
      
      const Product({
        required this.name,
        required this.id,
        required this.ingredients
      });
      
    }
    
    class ProductList extends ChangeNotifier
    {
      final _products = <Product>[];
      
      void add(Product product)
      {
        _products.add(product);
        notifyListeners();
      }
    
      Iterable<Product> get products => _products;
      
    }
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => ProductList()),
          ],
          child: MaterialApp(
            title: 'Flutter Demo',
            debugShowCheckedModeBanner: false,
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: const MyHomePage(title: 'Flutter Demo Home Page'),
          ),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      final String title;
    
      const MyHomePage({
        Key? key,
        required this.title,
      }) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
      void _incrementCounter() {
        context.read<ProductList>().add(const Product(name: 'Product 1', id: '1234', ingredients: ['Hello', 'There']));
      }
      
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: const SafeArea(
            child: Products(),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
        );
      }
    }
    
    class Products extends StatelessWidget {
      const Products({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            for(var product in context.watch<ProductList>().products)
              ListTile(
                leading: Text(product.id),
                title: Text(product.name),
                subtitle: Text(product.ingredients.join(', ')),
              ),
          ]
        );
      }
    }
    

    您可以在Dart Pad 上查看。希望这可以帮助。请参考How to create a Minimal, Reproducible Example

    【讨论】:

    • 哇!非常感谢,我现在将尝试使用它来重现问题
    • 如果有帮助我很高兴。
    【解决方案2】:

    对不起,这根本不是提供者的问题

    发生的事情是,当我将产品分配到产品列表时,成分列表是一个引用,在使用后被控制器清除,所以在代码中是这样的:

    
    List<String> ingredients = [];
    
    void onAddIngredient(){
      ingredients.add(ingredientController.text);
    }
    
    void onSubmit(){
    
      final myNewProduct = Product(
        name: nameController.text,
        id: idController.text, 
        ingredients:ingredients
      )
    
      providerAction(myNewProduct); // This is where it gets added to _products
    
      nameController.clear();
      idController.clear();
      ingredientController.clear();
      ingredients.clear(); // This was the problem where I was deleting the reference 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      • 2013-08-08
      • 2018-05-08
      • 1970-01-01
      • 2018-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多