Riverpod状态更改方法未按预期更改状态。

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

Riverpod state change methods not changing the state as intended

问题

以下是您要翻译的代码部分:

所以,我有一个在 riverpod 中的状态,它保存了一个集合的列表,然后我有两个方法,一个将其转换为数据库中所有集合的列表,另一个将状态仅限于今天的集合,如下所示:

u/riverpod
class SetsProvider extends _$SetsProvider {
  u/override
  List<Set> build() {
    return [];
  }

  void refresh() async {

         final data = await SQLHelper.getAllSets();

          state = data.map((e) => Set.fromJson(e)).toList();
  }



  void getTodaySets() async {

       final data = await SQLHelper.getTodayItems();

      state = data.map((e) => Set.fromJson(e)).toList();
  }
}

当我调用

final list = ref.watch(setsProviderProvider);

它完美地工作

但是当我尝试更改状态以仅返回今天的项目时,它就无法工作:

ref.read(setsProviderProvider.notifier).getTodaySets();

之后,当我观察 setProvider 时,它只会使我的列表为空。我可能做错了什么?

以下是我的 dbhelper 类:

import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart' as sql;
import 'set_model.dart';
import 'package:intl/intl.dart';

class SQLHelper {
  //创建表的方法
  static Future<void> createTables(sql.Database database) async {
    await database.execute("""CREATE TABLE sets(
      id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
      exerciseName TEXT,
      totalWeight TEXT,
      totalReps TEXT,
      date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      isFavorited INTEGER 
      )
      """);
    print('数据库已创建');
  }

  //打开名为 db 的数据库的方法
  static Future<sql.Database> db() async {
    return sql.openDatabase('dbsets.db', version: 1,
        onCreate: (sql.Database database, int version) async {
      await createTables(database); //调用上面的创建表方法
    });
  }

  static Future<int> insertSet(Set set) async {
    final db = await SQLHelper.db(); //打开数据库
    DateTime now = DateTime.now();
    String formattedDate = DateFormat('yyyy-MM-dd').format(now);
    //将日期更改为当前日期,这意味着我将在 Set 对象中将日期设置为非必需
    set.date == formattedDate;

    final id = await db.insert('sets', set.toJson(), //toJson 调用 map
        conflictAlgorithm: sql.ConflictAlgorithm.replace);

    return id;
  }

  static Future<List<Map<String, dynamic>>> getAllSets() async {
    final db = await SQLHelper.db();
    return db.query('sets', orderBy: 'id');
  }

  static Future<List<Map<String, dynamic>>> getTodayItems() async {
    final db = await SQLHelper.db(); //获取连接
    DateTime now = DateTime.now();
    String formattedDate = DateFormat('yyyy-MM-dd').format(now);
    final results =
        db.rawQuery('SELECT * FROM sets WHERE date = ?', [formattedDate]);
    print(results.toString());
    return results;
  }
}

以及我尝试在 Main.dart 中显示集合的地方:

child: ListView.builder(
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              itemCount: ref.watch(setsProviderProvider).length,
              itemBuilder: ((_, index) {
                ref.read(setsProviderProvider.notifier).getTodaySets();
                final list = ref.watch(setsProviderProvider);
                var set = list[index];
                return ListTile(
                  title: Text(set.exerciseName.toString()),
                  subtitle: Column(
                    children: [
                      Text(
                        set.totalWeight.toString(),
                      ),
                      Text(
                        set.totalReps.toString(),
                      )
                    ],
                  ),
                );
              }),
            ),
英文:

So I have a state in riverpod which holds a List of sets then I have two methods that make it a List of all the sets in the database and another that makes the state only today sets as follows:

u/riverpod
class SetsProvider extends _$SetsProvider {
u/override
List<Set> build() {
return [];
}
void refresh() async {
final data = await SQLHelper.getAllSets();
state = data.map((e) => Set.fromJson(e)).toList();
}
void getTodaySets() async {
final data = await SQLHelper.getTodayItems();
state = data.map((e) => Set.fromJson(e)).toList();
}

When I call

final list = ref.watch(setsProviderProvider);  

it works perfectly

But when I try to change the state to return only todays items it just doesn't work:

  ref.read(setsProviderProvider.notifier).getTodaySets();

it just makes my list empty when I watch the setProvider after that. What could I be doing wrong?

here is my dbhelper class:

import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart' as sql;
import 'set_model.dart';
import 'package:intl/intl.dart';
class SQLHelper {
//method to create table
static Future<void> createTables(sql.Database database) async {
await database.execute("""CREATE TABLE sets(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
exerciseName TEXT,
totalWeight TEXT,
totalReps TEXT,
date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
isFavorited INTEGER 
)
""");
print('Database created');
}
//method to open the database called db
static Future<sql.Database> db() async {
return sql.openDatabase('dbsets.db', version: 1,
onCreate: (sql.Database database, int version) async {
await createTables(database); //calling that create table method above
});
}
static Future<int> insertSet(Set set) async {
final db = await SQLHelper.db(); //opening the database
DateTime now = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd').format(now);
//Changing the Date to now meaning ill make the date not required in a Set object
set.date == formattedDate;
final id = await db.insert('sets', set.toJson(), //toJson calls the map
conflictAlgorithm: sql.ConflictAlgorithm.replace);
return id;
}
static Future<List<Map<String, dynamic>>> getAllSets() async {
final db = await SQLHelper.db();
return db.query('sets', orderBy: 'id');
}
static Future<List<Map<String, dynamic>>> getTodayItems() async {
final db = await SQLHelper.db(); //get connection
DateTime now = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd').format(now);
final results =
db.rawQuery('SELECT * FROM sets WHERE date = ?', [formattedDate]);
print(results.toString());
return results;
}
}

And where I am trying to show the sets in Main.dart:

   child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: ref.watch(setsProviderProvider).length,
itemBuilder: ((_, index) {
ref.read(setsProviderProvider.notifier).getTodaySets();
final list = ref.watch(setsProviderProvider);
var set = list[index];
return ListTile(
title: Text(set.exerciseName.toString()),
subtitle: Column(
children: [
Text(
set.totalWeight.toString(),
),
Text(
set.totalReps.toString(),
)
],
),
);
}),
),

答案1

得分: 0

首先,不要在 build 方法中进行数据库调用,因为它可能会运行多次。你可以将它放在诸如 initStatemain() 这样的地方。

列表没有更新,因为初始列表是空的,itemCount 为 0,所以 ListView 的项构建器从未被调用。

更新:我的意思是 Widget.build,而不是 providerbuild。最佳做法是在 providerbuild 中调用它,但这也会将 provider 更改为异步提供程序。

itemBuilder: ((_, index) {
    ref.read(setsProviderProvider.notifier).getTodaySets(); // <- 这不应该在这里/
    final list = ref.watch(setsProviderProvider);
英文:

First don't put database calls in during build, it might run multiple time.
You could put it in places such as initState or main().

The list didn't update because the initial list is empty, itemCount is 0, so item builder of ListView is never called.

Update: I meant Widget.build, not provider build. The best practice is to call it in provider's build, but this would also change the provider to async provider.

itemBuilder: ((_, index) {
ref.read(setsProviderProvider.notifier).getTodaySets(); // <- This shouldn't be here/
final list = ref.watch(setsProviderProvider);
</details>
# 答案2
**得分**: 0
你应该让筛选提供程序*监视*完整列表提供程序,同时将筛选参数作为家庭键。然后,当你更新完整列表提供程序(无论是来自本地变更还是观察数据库流),筛选提供程序将具有正确的值,并在被监视时进行缓存。
<details>
<summary>英文:</summary>
You should have the filter provider *watch* the full-list provider, as well as take a filter argument as a family key.  Then, as you update the full-list provider (either from local mutations, or from watching a database stream), the filter provider(s) will have the proper value, caching as long as they are being watched.
</details>

huangapple
  • 本文由 发表于 2023年7月23日 20:41:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76748298.html
匿名

发表评论

匿名网友

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

确定