ChangeNotifierProvider
The content of this page may be outdated.
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
ChangeNotifierProvider
(flutter_riverpod/hooks_riverpod only) is a provider that
is used to listen to and expose a ChangeNotifier from Flutter itself.
Using ChangeNotifierProvider
is discouraged by Riverpod and exists primarily for:
- an easy transition from
package:provider
when using itsChangeNotifierProvider
- supporting mutable state, even though immutable state is preferred
Prefer using NotifierProvider instead.
Consider using ChangeNotifierProvider
only if you are absolutely certain
that you want mutable state.
Using mutable state instead of immutable state can sometimes be more efficient.
The downside is, it can be harder to maintain and may break various features.
For example, using provider.select
to optimize rebuilds of your widgets
may not work if your state is mutable, as select
will think that the value
hasn't changed.
As such, using immutable data structures can sometimes be faster. Therefore
it is important to make benchmarks specific to your use-case, to make sure
that you are truly gaining performance by using ChangeNotifierProvider
.
As a usage example, we could use ChangeNotifierProvider
to implement a todo-list.
Doing so would allow us to expose methods such as addTodo
to let the UI
modify the list of todos on user interactions:
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>[];
// Let's allow the UI to add todos.
void addTodo(Todo todo) {
todos.add(todo);
notifyListeners();
}
// Let's allow removing todos
void removeTodo(String todoId) {
todos.remove(todos.firstWhere((element) => element.id == todoId));
notifyListeners();
}
// Let's mark a todo as completed
void toggle(String todoId) {
final todo = todos.firstWhere((todo) => todo.id == todoId);
todo.completed = !todo.completed;
notifyListeners();
}
}
// Finally, we are using ChangeNotifierProvider to allow the UI to interact with
// our TodosNotifier class.
final todosProvider = ChangeNotifierProvider<TodosNotifier>((ref) {
return TodosNotifier();
});
Now that we have defined a ChangeNotifierProvider
, we can use it to interact
with the list of todos in our UI:
class TodoListView extends ConsumerWidget {
const TodoListView({super.key});
Widget build(BuildContext context, WidgetRef ref) {
// rebuild the widget when the todo list changes
List<Todo> todos = ref.watch(todosProvider).todos;
// Let's render the todos in a scrollable list view
return ListView(
children: [
for (final todo in todos)
CheckboxListTile(
value: todo.completed,
// When tapping on the todo, change its completed status
onChanged: (value) =>
ref.read(todosProvider.notifier).toggle(todo.id),
title: Text(todo.description),
),
],
);
}
}