尽管观看提供商,UI 仍不更新

问题描述 投票:0回答:1

我正在使用 Riverpod 并为我的数据设置了提供程序和通知程序,但是当我修改提供程序中的数据时,我的 UI 没有反映该更改。如果我保存并热重新加载我的应用程序,则会显示新值。

就上下文而言,我的棋盘包含一个属性,即玩家及其分数的地图。在我的 Board 屏幕上,我正在迭代 GridView.builder 的“boardData”映射的列表转换,如下所示:

    ref.read(boardProvider.notifier).loadBoard(widget.board);
    final providedBoard = ref.watch(boardProvider);

    List<MapEntry<PlayerModel, int>> boardDataList =
        providedBoard.boardData.entries.toList();


      body: GridView.builder(
        padding: const EdgeInsets.all(16),
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          childAspectRatio: 3 / 2, //1.5
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
        ),
        itemCount: providedBoard.boardData.length,
        itemBuilder: (context, index) => BoardPlayerGridItem(
          player: boardDataList[index].key,
          score: boardDataList[index].value,
        ),
      ),

这是我的提供者:

class BoardNotifier extends StateNotifier<BoardModel> {
  BoardNotifier() : super(sampleBoard);

  // Load the currently viewed board into notifier
  loadBoard(BoardModel board) {
    state = board;
  }

  // Update the player's score in the board by the configured increment
  incrementPlayerScore(BoardModel board, PlayerModel player) {
    board.boardData.update(player, (value) => value + board.increment);

    // Update our board in state
    state = board;
  }
}

final boardProvider = StateNotifierProvider<BoardNotifier, BoardModel>((ref) {
  return BoardNotifier();
});

这是我的 BoardPlayerGridItem(GridView 中的小部件),它没有更新。

class BoardPlayerGridItem extends ConsumerStatefulWidget {
  const BoardPlayerGridItem({
    super.key,
    required this.player,
    required this.score,
  });

  final PlayerModel player;
  final int? score;

  @override
  ConsumerState<ConsumerStatefulWidget> createState() =>
      _BoardPlayerGridItemState();
}

class _BoardPlayerGridItemState extends ConsumerState<BoardPlayerGridItem> {
  @override
  Widget build(BuildContext context) {
    final providedBoard = ref.watch(boardProvider);

    return GestureDetector(
      onTap: () {
        ref.watch(boardProvider.notifier).incrementPlayerScore(
              providedBoard,
              widget.player,
            );
      },
      onLongPress: () {}, // Open edit form
      child: Container(
        color: Theme.of(context).highlightColor,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              widget.player.name,
              style: Theme.of(context)
                  .textTheme
                  .titleMedium!
                  .copyWith(color: Theme.of(context).colorScheme.onBackground),
            ),
            const SizedBox(height: 10),
            Text(
              widget.score.toString(),
              style: Theme.of(context)
                  .textTheme
                  .displayLarge!
                  .copyWith(color: Theme.of(context).colorScheme.onBackground),
            ),
          ],
        ),
      ),
    );
  }
}

用户界面是一个图块网格,点击每个图块都会增加计数器。我想通过添加监视我的 boardProvider,然后根据 onTap 函数更改它,这会提示重建,但似乎没有。任何指示都适用。

flutter dart provider riverpod
1个回答
0
投票

问题是在

incrementPlayerScore
内部,您在重新分配
state
之前已经更新了面板。这就是为什么使用不可变状态很重要。

作为解决方法,您可以在

incrementPlayerScore
内创建一个局部变量,首先复制
board
状态,然后对复制的变量进行修改。您还没有显示
BoardModel
类,但我认为它应该有某种
copyWith
方法。如果是这样,你可以这样做:

incrementPlayerScore(BoardModel board, PlayerModel player) {
  final newBoard = board.copyWith();
  newBoard.boardData.update(player, (value) => value + board.increment);

  // Update our board in state
  state = newBoard;
}

(注意:可能有更好的方法来使用

copyWith
,即通过
boardData
boardData
参数分配新的
copyWith


此外,您应该在

ref.read
ref.watch
内使用
onTap
而不是
GestureDetector

© www.soinside.com 2019 - 2024. All rights reserved.