Flutter Riverpod可变引用问题:修改本地列表致Provider值变更
问题:修改本地列表时意外改动了Provider中的数据
代码示例
static List<Ball> calculateAllMoveCordsForHardMove(int wichBoard) { final List<Ball> moveList = navigatorKey.currentContext!.read(gameStatusProvider).moves; print( 'Cord(${moveList[0].cord?.x.toString()}, ${moveList[0].cord?.y.toString()})'); for (int i = 0; i < moveList.length; i++) { final boardNumber = moveList[i].wichBoard ?? 0; if (boardNumber == wichBoard) { final cord = moveList[i].cord ?? Cord(0, 0); final newCord = nextCord(cord, boardNumber);//just returns a cord moveList[i].cord = newCord; } } final moves2 = navigatorKey.currentContext!.read(gameStatusProvider).moves; print( 'Cord(${moves2[0].cord?.x.toString()}, ${moves2[0].cord?.y.toString()})'); return moves; }
运行输出
flutter: Cord(0, 2) flutter: Cord(0, 0)
问题分析
你的判断正确:read返回的是Provider中列表的可变引用,且Ball是可变对象,修改moveList中元素的属性时,会直接修改Provider里的原数据。要实现仅修改本地列表,需要对原列表做深拷贝,彻底切断与原数据的引用关联。
解决方案
方法1:利用copyWith方法(推荐)
如果你的Ball类定义了copyWith方法(Flutter模型类的常规写法),可以通过map生成新的Ball实例,再转为新列表:
final List<Ball> moveList = navigatorKey.currentContext!.read(gameStatusProvider).moves .map((ball) => ball.copyWith()) .toList();
copyWith方法示例(需在Ball类中实现):
class Ball { final Cord? cord; final int? wichBoard; // 其他属性 Ball({this.cord, this.wichBoard}); Ball copyWith({ Cord? cord, int? wichBoard, // 其他属性参数 }) { return Ball( cord: cord ?? this.cord, wichBoard: wichBoard ?? this.wichBoard, // 其他属性赋值 ); } }
方法2:手动创建新实例
如果没有copyWith方法,直接手动复制每个Ball的属性生成新对象:
final List<Ball> moveList = navigatorKey.currentContext!.read(gameStatusProvider).moves .map((ball) => Ball( cord: ball.cord != null ? Cord(ball.cord!.x, ball.cord!.y) : null, wichBoard: ball.wichBoard, // 复制Ball类的其他所有属性 )) .toList();
效果验证
修改后,moveList是完全独立的本地列表,修改其中的cord属性不会影响Provider中的原数据,第二次打印的moves2会和第一次打印的初始值一致。
内容的提问来源于stack exchange,提问作者gevoid
相关产品推荐
相关产品推荐

