Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
433 views
in Technique[技术] by (71.8m points)

(Flutter / Riverpod) Should not ProviderReference.read inside the body of a provider at Riverpod be used in any case?

I have a question about how to use ProviderReference.read in Riverpod.

I found a caution not to DON'T CALL ProviderReference.read INSIDE THE BODY OF A PROVIDER in the following formal site.

Can I read a provider without listening to it? https://riverpod.dev/docs/concepts/combining_providers/#can-i-read-a-provider-without-listening-to-it

DON'T CALL READ INSIDE THE BODY OF A PROVIDER

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

But, on the other hand, I found another example about ProviderReference.read in the following page, in which ref.read are used in inside the body of a provider.

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

Creating an object that depends on a lot of providers.
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)';
}

So, I would like to question: still I should not call ProviderReference.read in inside the body of a provider?

If yes, let me question another: What should I do about the following my code in which I use ProviderReference.read in inside the body of a provider. I hope someone give me a good idea.

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;
}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I think the point is that it's not wrong, it's bad practice. The correct way to do it is to pass the ProviderReference to the StateNotifier as an argument :

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

and then in the StateNotifier :

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...