Riverpod 状态更新不会重建小部件

Sas*_*asa 4 dart flutter riverpod

我正在使用StateProvider<List<String>>来跟踪井字游戏板上的用户点击。实际板是一个扩展ConsumerWidget 的小部件,由可点击的 GridView 组成。

在GridViews 子级的onTap事件中,调用以下命令来更新状态:

ref.read(gameBoardStateProvider.notifier).state[index] = 'X';
Run Code Online (Sandbox Code Playgroud)

由于某种原因,这不会调用小部件重建事件。因此,我看不到被点击的 GridView 项目中的“X”。

但是,如果我添加额外的“简单”StateProvider<int> 并在同一 onTap 事件中调用它,那么小部件将被重建,并且我可以在 GridView 中看到“X”。我什至没有使用或显示这个附加的状态提供程序,但由于某种原因它会调用重建,而我想要的提供程序却不会。

final gameBoardStateProvider = StateProvider<List<String>>((ref) => List.filled(9, '', growable: false));

final testStateProvider = StateProvider<int>((ref) => 0); //dummy state provider

class Board extends ConsumerWidget {
  const Board({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final gameBoard = ref.watch(gameBoardStateProvider);
    final testState = ref.watch(testStateProvider);

    return Expanded(
      child: Center(
        child: GridView.builder(
          itemCount: 9,
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
          shrinkWrap: true,
          itemBuilder: ((BuildContext context, int index) {
            return InkWell(
              onTap: () {
                //With this line only the widget does not get refreshed - and I do not see board refreshed with added 'X'
                ref.read(gameBoardStateProvider.notifier).state[index] = 'X';
                //??? If I add this line as well - for some reason the widget get refreshed - and I see board refreshed with added 'X'
                ref.read(testStateProvider.notifier).state++;
              },
              child: Container(
                decoration: BoxDecoration(border: Border.all(color: Colors.white)),
                child: Center(
                  child: Text(gameBoard[index]),
                ),
              ),
            );
          }),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Md.*_*ikh 6

一旦你这样做了

ref.read(gameBoardStateProvider.notifier).state[index] = 'X'
Run Code Online (Sandbox Code Playgroud)

意味着改变单个变量。为了更新 UI,您需要提供一个新列表作为 State。

你可以这样做

List<String> oldState = ref.read(gameBoardStateProvider);
oldState[index] = "X";
ref
    .read(gameBoardStateProvider.notifier)
    .update((state) => oldState.toList());
Run Code Online (Sandbox Code Playgroud)

或者

List<String> oldState = ref.read(gameBoardStateProvider);
oldState[index] = "X";
ref.read(gameBoardStateProvider.notifier).state =
    oldState.toList();
Run Code Online (Sandbox Code Playgroud)

为什么testStateProvider有效:

因为它包含单个 int 作为 State,其中gameBoardStateProvider包含List<String>作为 State。

仅更新单个变量不会刷新 ui state_provider,需要更新状态来强制刷新

更多关于state_provider

您还可以检查change_notifier_provider