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
相关产品推荐
相关产品推荐

