使用Riverpod基于另一个状态初始化一个通知器

huangapple go评论68阅读模式
英文:

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实现这种一对多关系。

使用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 &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter_riverpod/flutter_riverpod.dart&#39;;
import &#39;package:todo/models/group.dart&#39;;
import &#39;package:todo/db/db_helper.dart&#39; as dbHelper;
import &#39;package:todo/providers/tasks_provider.dart&#39;;

class GroupsNotifier extends StateNotifier&lt;List&lt;Group&gt;&gt; {
  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&lt;GroupsNotifier, List&lt;Group&gt;&gt;((ref) {
  return GroupsNotifier();
});

and
tasks_provider.dart

import &#39;package:flutter_riverpod/flutter_riverpod.dart&#39;;
import &#39;package:todo/models/group.dart&#39;;
import &#39;package:todo/models/task.dart&#39;;
import &#39;package:todo/db/db_helper.dart&#39; as dbHelper;
import &#39;package:todo/providers/groups_provider.dart&#39;;

class TasksNotifier extends StateNotifier&lt;Map&lt;Group, List&lt;Task&gt;&gt;&gt; {
  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&lt;Task&gt; tasks = state[group]!;

    final index = tasks.indexOf(task);
    List&lt;Task&gt; newList = [];
    bool newValue = false;
    for (var i = 0; i &lt; 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&lt;TasksNotifier, Map&lt;Group, List&lt;Task&gt;&gt;&gt;((ref) {
  return TasksNotifier();
});

I use sqflite to work with SQLite database.

Because reading from database is an async task

class _TasksInCardState extends ConsumerState&lt;TasksInCard&gt; {
  List&lt;Task&gt; 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 []

使用Riverpod基于另一个状态初始化一个通知器

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&#39;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&lt;List&lt;Task&gt;&gt; {
  final Group group;

  GrouTasksNotifier(this.group) : super(const []);

  Future&lt;void&gt; loadTasks() async {
    state = await dbHelper.getTasksByGroup(group);
  }

  Future&lt;void&gt; 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&lt;GrouTasksNotifier, List&lt;Task&gt;, Group&gt;((ref, group) {
  return GrouTasksNotifier(group);
});

huangapple
  • 本文由 发表于 2023年7月14日 06:54:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76683738.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定