Riverpod:列表提供者没有重建

Riverpod: List provider is not rebuilding

StateNotifier 的类型为 List 时,Flutter riverpod 不会通知 Consumer 状态更改,而相同的实现对其他类型也适用。

在这里,我提供了一个最小的可重现示例:

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ProviderScope(
      child: MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

class CounterState extends StateNotifier<List<int>> {
  static final provider = StateProvider(
    (ref) => CounterState(),
  );

  int get last {
    print('last');
    return state.last;
  }

  int get length {
    print('len');
    return state.length;
  }

  // the body of this will be provided below
  add(int p) {}

  CounterState() : super(<int>[0]);
}

class MyHomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, watch) {
    void _incrementCounter() {
      final _count = Random.secure().nextInt(100);

      context.read(CounterState.provider.notifier).state.add(_count);
    }

    var count = watch(CounterState.provider.notifier).state.length;

    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text(
          'You have pushed the button this many times: $count',
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: Icon(Icons.add),
      ),
    );
  }
}

至于add方法,我尝试了很多方法,但都不行。

这是我尝试过的:

1:直接添加即可:

add(int p) {
  state.add(p);
}

2:我也尝试了中建议的解决方案:

add(int p) {
  state = [...state, p];
}

3:我试图完全销毁列表,然后重新分配它:

add(int p) {
  final _state = [];

  // copy [state] to [_state]
  for (var item in state) {
    _state.add(item);
  }

  // empty the state
  state = [];

  // add the new element
  _state.add(p);

  // refill [state] from [_state]
  for (var item in _state) {
    state.add(item);
  }


  print(state.length); // it continues until here and prints
}

首先,您没有创建正确的提供商来收听 StateNotifier。你需要改变这个:

static final provider = StateProvider(
  (ref) => CounterState(),
);

对此:

static final provider = StateNotifierProvider<CounterState, List<int>>(
  (ref) => CounterState(),
);

有关不同类型的提供商,请参阅 Riverpod 文档。

其次,您实际上并不是在监视状态变化,而只是从通知程序获取状态对象。

更改此行:

var count = watch(CounterState.provider.notifier).state.length;

对此:

final count = watch(CounterState.provider).length;

此外,您的增量方法对于 StateNotifier 供应商不正确。请更改此设置:

context.read(CounterState.provider.notifier).state.add(_count);

对此:

context.read(CounterState.provider.notifier).add(_count);

当状态改变时应该立即重建。但是,您确实需要一个实际更改状态对象本身的 add 方法的实现。我会建议你提到的第二个变体,在我看来这是最好的方法:

add(int p) {
  state = [...state, p];
}

@TmKVU 解释得很好,所以我跳过了那部分。也可以关注riverpod文档

这是我的 riverPod 示例:

您的小部件

import 'dart:math';

import 'package:stack_overflow/exports.dart';

class CounterState extends StateNotifier<List<int>> {
  static final provider = StateNotifierProvider(
    (ref) => CounterState(),
  );

  int get last {
    print('last');
    return state.last;
  }

  int get length {
    print('len');
    return state.length;
  }

  // the body of this will be provided below
  add(int p) {}

  CounterState() : super(<int>[0]);
}

class MyHomePageSSSS extends ConsumerWidget {
  @override
  Widget build(BuildContext context, watch) {
    void _incrementCounter() {
      final _count = Random.secure().nextInt(100);

      context.read(CounterState.provider.notifier).state =
          context.read(CounterState.provider.notifier).state..add(_count);
    }

    final countprovider = watch(CounterState.provider);

    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text(
          'You have pushed the button this many times: ${countprovider.length}',
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: Icon(Icons.add),
      ),
    );
  }
}