(Flutter / Riverpod) 在任何情况下都不应使用 Riverpod 提供者体内的 ProviderReference.read 吗?

时间:2021-01-11 10:33:49

标签: flutter riverpod

我有一个关于如何在 Riverpod 中使用 ProviderReference.read 的问题。

我发现了一个警告,不要在以下正式站点中调用 ProviderReference.read INSIDE THE BODY OF A Provider。

我可以在不听的情况下阅读提供者吗? https://riverpod.dev/docs/concepts/combining_providers/#can-i-read-a-provider-without-listening-to-it

<块引用>

不要在供应商的身体内打电话

final myProvider = Provider((ref) {
  // Bad practice to call `read` here
  final value = ref.read(anotherProvider);
});

但是,另一方面,我在下一页找到了另一个关于 ProviderReference.read 的例子, 其中 ref.read 用于提供者的主体内部。

https://pub.dev/documentation/riverpod/latest/all/Provider-class.html

创建一个依赖于许多提供者的对象。
final cityProvider = Provider((ref) => 'London');
final countryProvider = Provider((ref) => 'England');

final weatherProvider = Provider((ref) {
  final city = ref.read(cityProvider);   // <------------------- `ref.read` is used 
  final country = ref.read(countryProvider);  // <-------------- `ref.read` is used 

  return Location(city: city, country: country);
});

class Location {
  Location({this.city, this.country});

  final String city;
  final String country;

  String get label => '$city ($country)';
}

所以,我想问一下:我仍然不应该在提供者的主体内部调用 ProviderReference.read 吗?

如果是的话,让我再问一个问题: 我应该如何处理以下我在提供程序主体内使用 ProviderReference.read 的代码。 我希望有人给我一个好主意。

final todoListProvider = StateNotifierProvider<TodoListController>((ref) {
  final todosRepository = ref.read(repositoryProvider); // <---------- using `ref.read` here.
  return TodoListController(
    todosRepository: todosRepository,
  );
});

class TodoListController extends StateNotifier<TodoListState> {
  TodoListController({
    List<Todo> todos = const [],
    @required this.todosRepository,
  })  : assert(todosRepository != null),
        super(TodoListState(todos, loading: false)) {
    _loadTodos();
  }

  final TodosRepository todosRepository;

  Future<void> _loadTodos() async {
    state = (state.copyWith(loading: true));

    final todos = await todosRepository.loadTodos();

    state = (state.copyWith(
      todos: todos.map(Todo.fromEntity).toList(),
      loading: false,
    ));
  }
}

@freezed
abstract class TodoListState with _$TodoListState {
  const factory TodoListState({
    List<Todo> todos, {
    @required bool loading,
  }) = _TodoListState;
}

1 个答案:

答案 0 :(得分:0)

我认为重点是这没有错,这是不好的做法。正确的做法是将 ProviderReference 作为参数传递给 StateNotifier :

Provider((ref) => TodoListController(ref,
    todosRepository: todosRepository,
  );)

然后在 StateNotifier 中:

// constructor
TodoListController(this._ref, [...]);
// the reference as a class member
final ProviderReference _ref;