我正在使用 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 函数更改它,这会提示重建,但似乎没有。任何指示都适用。
问题是在
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
。