I am trying to implement similar functionality to the basic example given in the Riverpod docs: https://riverpod.dev/docs/providers/notifier_provider
Relevant code from docs with most comments removed, notifier:
@riverpod
class Todos extends _$Todos {
@override
List<Todo> build() {
return [];
}
void addTodo(Todo todo) {
state = [...state, todo];
}
void removeTodo(String todoId) {
state = [
for (final todo in state)
if (todo.id != todoId) todo,
];
}
void toggle(String todoId) {
state = [
for (final todo in state)
if (todo.id == todoId)
todo.copyWith(completed: !todo.completed)
else
todo,
];
}
}
Ui widget:
class TodoListView extends ConsumerWidget {
const TodoListView({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// rebuild the widget when the todo list changes
List<Todo> todos = ref.watch(todosProvider);
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),
),
],
);
}
}
Note the part in the code with the comment: // rebuild the widget when the todo list changes
. The author seems to be aware that this will trigger the whole list to rebuild when you complete one task.
How do I avoid this? I was thinking that if I used a ListView
with a builder I could maybe somehow use select, and only listen to one element from the array, but it seems that you can only listen to properties directly from the state, and since the state is an array that seems impossible? I would like an example how to design it in such a way to select only one element of the array to achieve rebuilding only one widget that changed.