英文:
Riverpod Initialize a notifier based on another state
问题
我想要实现一个简单的待办事项应用程序。我有两个实体:分组(Groups)和任务(Tasks),其中每个分组可以有多个任务。
我有两个提供者:
groups_provider.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:todo/models/group.dart';
import 'package:todo/db/db_helper.dart' as dbHelper;
import 'package:todo/providers/tasks_provider.dart';
class GroupsNotifier extends StateNotifier<List<Group>> {
GroupsNotifier() : super([]);
void loadGroups() async {
state = await dbHelper.getAllGroups();
}
void addGroup(String title, Color color) async {
final newId = await dbHelper.addGroup(title, color);
final newGroup = Group(id: newId, title: title, color: color);
state = [...state, newGroup];
}
}
final groupsProvider =
StateNotifierProvider<GroupsNotifier, List<Group>>((ref) {
return GroupsNotifier();
});
和
tasks_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:todo/models/group.dart';
import 'package:todo/models/task.dart';
import 'package:todo/db/db_helper.dart' as dbHelper;
import 'package:todo/providers/groups_provider.dart';
class TasksNotifier extends StateNotifier<Map<Group, List<Task>>> {
TasksNotifier() : super({});
void loadTasks(Group group) async {
state = {...state, group: await dbHelper.getTasksByGroup(group)};
}
void addTask(String title, Group group, bool done) async {
final newId = await dbHelper.addTask(title, group, done);
final newTask = Task(id: newId, title: title, group: group, done: done);
state = {
...state,
group: [...state[group] ?? [], newTask]
};
}
void toggleDone(Task task) {
final group = task.group;
final List<Task> tasks = state[group]!;
final index = tasks.indexOf(task);
List<Task> newList = [];
bool newValue = false;
for (var i = 0; i < state.length; i++) {
newValue = index == i ? !tasks[i].done : tasks[i].done;
newList.add(
Task(
id: tasks[i].id,
title: tasks[i].title,
group: tasks[i].group,
done: newValue),
);
}
dbHelper.changeTaskDone(task, newValue);
state = {...state, group: newList};
}
}
final tasksProvider =
StateNotifierProvider<TasksNotifier, Map<Group, List<Task>>>((ref) {
return TasksNotifier();
});
我使用sqflite
来处理SQLite数据库。
由于从数据库中读取数据是一个异步任务
class _TasksInCardState extends ConsumerState<TasksInCard> {
List<Task> tasks = [];
@override
void initState() {
super.initState();
ref.read(tasksProvider.notifier).loadTasks(widget.group);
}
@override
Widget build(BuildContext context) {
tasks = ref.watch(tasksProvider)[widget.group] ?? [];
return Expanded(
child: Directionality(
textDirection: TextDirection.rtl,
child: ListView.builder(
// ...
),
),
);
}
}
第一次调用的任务是 []
通常,如何使用Riverpod实现这种一对多关系。
英文:
I want to implement a simple to-do app. I have two entities: Groups and Tasks, where each group can have multiple tasks.
I have two providers:
groups_provider.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:todo/models/group.dart';
import 'package:todo/db/db_helper.dart' as dbHelper;
import 'package:todo/providers/tasks_provider.dart';
class GroupsNotifier extends StateNotifier<List<Group>> {
GroupsNotifier() : super([]);
void loadGroups() async {
state = await dbHelper.getAllGroups();
}
void addGroup(String title, Color color) async {
final newId = await dbHelper.addGroup(title, color);
final newGroup = Group(id: newId, title: title, color: color);
state = [...state, newGroup];
}
}
final groupsProvider =
StateNotifierProvider<GroupsNotifier, List<Group>>((ref) {
return GroupsNotifier();
});
and
tasks_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:todo/models/group.dart';
import 'package:todo/models/task.dart';
import 'package:todo/db/db_helper.dart' as dbHelper;
import 'package:todo/providers/groups_provider.dart';
class TasksNotifier extends StateNotifier<Map<Group, List<Task>>> {
TasksNotifier() : super({});
void loadTasks(Group group) async {
state = {...state, group: await dbHelper.getTasksByGroup(group)};
}
void addTask(String title, Group group, bool done) async {
final newId = await dbHelper.addTask(title, group, done);
final newTask = Task(id: newId, title: title, group: group, done: done);
state = {
...state,
group: [...state[group] ?? [], newTask]
};
}
void toggleDone(Task task) {
final group = task.group;
final List<Task> tasks = state[group]!;
final index = tasks.indexOf(task);
List<Task> newList = [];
bool newValue = false;
for (var i = 0; i < state.length; i++) {
newValue = index == i ? !tasks[i].done : tasks[i].done;
newList.add(
Task(
id: tasks[i].id,
title: tasks[i].title,
group: tasks[i].group,
done: newValue),
);
}
dbHelper.changeTaskDone(task, newValue);
state = {...state, group: newList};
}
}
final tasksProvider =
StateNotifierProvider<TasksNotifier, Map<Group, List<Task>>>((ref) {
return TasksNotifier();
});
I use sqflite
to work with SQLite database.
Because reading from database is an async task
class _TasksInCardState extends ConsumerState<TasksInCard> {
List<Task> tasks = [];
@override
void initState() {
super.initState();
ref.read(tasksProvider.notifier).loadTasks(widget.group);
}
@override
Widget build(BuildContext context) {
tasks = ref.watch(tasksProvider)[widget.group]??[];
return Expanded(
child: Directionality(
textDirection: TextDirection.rtl,
child: ListView.builder(
....
tasks in first call is []
Generally, how can I implement this one-to-many relationship with Riverpod.
答案1
得分: 0
我不确定这是否能解决您的问题,但您可以将以下代码更改为:
```dart
void loadTasks(Group group) async {
final groupTasks = await dbHelper.getTasksByGroup(group);
state = {...state, group: groupTasks};
}
或者使用一个 family provider:
class GrouTasksNotifier extends StateNotifier<List<Task>> {
final Group group;
GrouTasksNotifier(this.group) : super(const []);
Future<void> loadTasks() async {
state = await dbHelper.getTasksByGroup(group);
}
Future<void> addTask(String title, bool done) async {
final newId = await dbHelper.addTask(title, group, done);
final newTask = Task(id: newId, title: title, group: group, done: done);
state = [...state, newTask];
}
void toggleDone(Task task) {
final newValue = !task.done;
dbHelper.changeTaskDone(task, newValue);
final updatedState = state.map((t) {
if (t.id == task.id) {
return Task(
id: task.id,
title: task.title,
group: task.group,
done: newValue,
);
} else {
return t;
}
}).toList();
state = updatedState;
}
}
final groupTasksProvider = StateNotifierProvider.family<GrouTasksNotifier, List<Task>, Group>((ref, group) {
return GrouTasksNotifier(group);
});
<details>
<summary>英文:</summary>
I'm not sure it will fix your issue but you could change :
```dart
void loadTasks(Group group) async {
state = {...state, group: await dbHelper.getTasksByGroup(group)};
}
to:
void loadTasks(Group group) async {
final groupTasks = await dbHelper.getTasksByGroup(group);
state = {...state, group: groupTasks};
}
Or using a family provider:
class GrouTasksNotifier extends StateNotifier<List<Task>> {
final Group group;
GrouTasksNotifier(this.group) : super(const []);
Future<void> loadTasks() async {
state = await dbHelper.getTasksByGroup(group);
}
Future<void> addTask(String title, bool done) async {
final newId = await dbHelper.addTask(title, group, done);
final newTask = Task(id: newId, title: title, group: group, done: done);
state = [...state, newTask];
}
void toggleDone(Task task) {
final newValue = !task.done;
dbHelper.changeTaskDone(task, newValue);
final updatedState = state.map((t) {
if (t.id == task.id) {
return Task(
id: task.id,
title: task.title,
group: task.group,
done: newValue,
);
} else {
return t;
}
}).toList();
state = updatedState;
}
}
final groupTasksProvider = StateNotifierProvider.family<GrouTasksNotifier, List<Task>, Group>((ref, group) {
return GrouTasksNotifier(group);
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论