К содержимому

ChangeNotifierProvider

ChangeNotifierProvider (есть только в flutter_riverpod/hooks_riverpod) - это провайдер, который можно прослушивать, а также он хранит в себе ChangeNotifier из Flutter.

Использование ChangeNotifierProvider не поощряется Riverpod. Но все же этот провайдер нужен для:

  • простого перехода с package:provider и его ChangeNotifierProvider
  • поддержки изменяемых состояний, хотя неизменяемые - предпочтительней
к сведению

Рекомендуется использовать StateNotifierProvider. Используйте ChangeNotifierProvider только, когда вы абсолютно уверены, что вам нужно изменяемое состояние.

Использование изменяемого состояние вместо неизменяемого иногда может быть более эффективно. Минус заключается в том, что с изменяемым состоянием бывает сложнее поддерживать приложение, а также это может поломать некоторый функционал. Например использование provider.select для оптимизации перестроек виджетов может не сработать, если ваше состояние изменяемо, т. к. select не заметит изменения состояния. Использование неизменяемых структур данных иногда работает быстрее. Поэтому важно делать бенчмарки конкретно вашего случая, чтобы убедиться, действительно ли вы повышаете производительность, используя ChangeNotifierProvider.

В качестве примера мы можем использовать ChangeNotifierProvider для реализации списка задач.


class Todo {
Todo({
required this.id,
required this.description,
required this.completed,
});

String id;
String description;
bool completed;
}

class TodosNotifier extends ChangeNotifier {
final todos = <Todo>[];

// Добавление задач
void addTodo(Todo todo) {
todos.add(todo);
notifyListeners();
}

// Удаление задач
void removeTodo(String todoId) {
todos.remove(todos.firstWhere((element) => element.id == todoId));
notifyListeners();
}

// Задача выполнена/не выполнена
void toggle(String todoId) {
for (final todo in todos) {
if (todo.id == todoId) {
todo.completed = !todo.completed;
notifyListeners();
}
}
}
}

// Используем ChangeNotifierProvider для взаимодействия с TodosNotifier
final todosProvider = ChangeNotifierProvider<TodosNotifier>((ref) {
return TodosNotifier();
});

Теперь, когда мы объявили ChangeNotifierProvider, мы можем использовать его для взаимодействия со списком задач:


class TodoListView extends ConsumerWidget {
const TodoListView({super.key});


Widget build(BuildContext context, WidgetRef ref) {
// перестройка виджета, когда список задач изменился
List<Todo> todos = ref.watch(todosProvider).todos;

// Отображение задач в прокручиваемом списке
return ListView(
children: [
for (final todo in todos)
CheckboxListTile(
value: todo.completed,
// По клику меняем статус задачи
// выполнена/не выполнена
onChanged: (value) =>
ref.read(todosProvider.notifier).toggle(todo.id),
title: Text(todo.description),
),
],
);
}
}