Reputation: 47
My question maybe is simple. I saw tutorials of future provider when loading a page but not in a situation when the user clicks a button or performs an action. Can you share some links of examples where by clicking a button a future provider is used in the same page? I just need something to point me in the right direction.
Upvotes: 2
Views: 833
Reputation: 4844
Your answer is as simple as your question :) Consider using AsyncNotifierProvider. This will allow you to have the necessary methods to change your "future state".
In a nutshell, it looks like this:
@immutable
class Todo {
const Todo({
required this.id,
required this.description,
required this.completed,
});
factory Todo.fromJson(Map<String, dynamic> map) {
return Todo(
id: map['id'] as String,
description: map['description'] as String,
completed: map['completed'] as bool,
);
}
final String id;
final String description;
final bool completed;
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'description': description,
'completed': completed,
};
}
class AsyncTodosNotifier extends AsyncNotifier<List<Todo>> {
Future<List<Todo>> _fetchTodo() async {
final json = await http.get('api/todos');
final todos = jsonDecode(json) as List<Map<String, dynamic>>;
return todos.map(Todo.fromJson).toList();
}
@override
Future<List<Todo>> build() async {
return _fetchTodo();
}
Future<void> toggle(String todoId) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
await http.patch(
'api/todos/$todoId',
<String, dynamic>{'completed': true},
);
return _fetchTodo();
});
}
}
final asyncTodosProvider =
AsyncNotifierProvider<AsyncTodosNotifier, List<Todo>>(AsyncTodosNotifier.new);
Your Widget Consumer:
class TodoListView extends ConsumerWidget {
const TodoListView({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncTodos = ref.watch(asyncTodosProvider);
return asyncTodos.when(
data: (todos) => ListView(
children: [
for (final todo in todos)
CheckboxListTile(
value: todo.completed,
onChanged: (value) =>
ref.read(asyncTodosProvider.notifier).toggle(todo.id),
title: Text(todo.description),
),
],
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, stack) => Text('Error: $err'),
);
}
}
Upvotes: 3