You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何通过Signals实现列表元素属性更新触发Widget重建

问题

使用signals库的ListSignal作为ListView的数据源时,添加或移除列表元素能正常触发ListView重建,但修改列表中ScannedProduct对象的quantity属性时,无法触发对应MyCard Widget的更新。现有代码如下,请问执行products[0].quantity++时,如何触发Widget重建?

class ScannedProduct {
  final String name;
  final int quantity;

  ScannedProduct({required this.name, required this.quantity});
}

class MyCard extends StatelessWidget {
  final ScannedProduct product;

  MyCard({required this.product});

  Widget build(BuildContext context) {
    return Card(
      child: Row(
        children: [
          Text(product.name),
          Text(product.quantity.toString())
        ]
      )
    );
  }
}

class MyScreen extends StatefulWidget<_MyScreenState> {
  // 省略部分代码
}

class _MyScreenState extends State<MyScreenState> {
    ListSignal<ScannedProduct> products = ListSignal([]);

    Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: products.length,
      itemBuilder: (context, index) => MyCard(
        product: products[index]
      )
    );
  }
}

已知执行products.add(ScannedProduct('SomeProduct', 1));可正常触发重建,如何实现products[0].quantity++;时触发更新?


解决方案

方法1:用Signal包装对象内部属性

将ScannedProduct的属性改为Signal类型,让内部属性的变化能被监听,同时MyCard需要通过watch绑定信号:

class ScannedProduct {
  final String name;
  final ValueSignal<int> quantity;

  ScannedProduct({required this.name, required int quantity}) 
      : quantity = ValueSignal(quantity);
}

class MyCard extends StatelessWidget {
  final ScannedProduct product;

  MyCard({required this.product});

  Widget build(BuildContext context) {
    // 监听quantity的变化
    final quantity = product.quantity.watch(context);
    return Card(
      child: Row(
        children: [
          Text(product.name),
          Text(quantity.toString())
        ]
      )
    );
  }
}

修改quantity时直接操作Signal的value:

products[0].quantity.value++;

方法2:替换列表中的元素

ListSignal能检测到元素的替换操作,所以修改quantity时,创建新的ScannedProduct对象替换原位置元素:

// 修改quantity的方式
final updatedProduct = ScannedProduct(
  name: products[0].name,
  quantity: products[0].quantity + 1,
);
products[0] = updatedProduct;

这种方法不需要改动ScannedProduct和MyCard的原有代码,适合不想调整数据结构的场景。

方法3:用MutableSignal包装整个对象

如果希望对象的所有属性变化都能被监听,可以用MutableSignal包装ScannedProduct,同时调整ListSignal的类型:

class ScannedProduct {
  String name;
  int quantity;

  ScannedProduct({required this.name, required this.quantity});
}

class _MyScreenState extends State<MyScreenState> {
    ListSignal<MutableSignal<ScannedProduct>> products = ListSignal([]);

    Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: products.length,
      itemBuilder: (context, index) {
        final productSignal = products[index].watch(context);
        return MyCard(product: productSignal);
      }
    );
  }
}

修改quantity时:

products[0].value.quantity++;
// 若自动检测不到变化,手动触发更新
products[0].set(products[0].value);

内容的提问来源于stack exchange,提问作者cmpbedes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:47:39