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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:27:27