[英]How to use a list of objects in a provider with Riverpod
我正在構建一個 Flutter 應用程序,並且正在努力解決整個提供者/消費者概念以及如何使用 Riverpod 解決我的問題。 我之前沒有與供應商/消費者合作過,所以我很難理解它。
下面我有一個示例圖和我試圖滿足的要求。
基本上,我有一個表格 object,我想在提供商中使用它,因為應用程序的各個地方都需要它。 object 有更新其 state 的方法。
來自 getForm() 的小部件更新數據,當數據更新時(用戶點擊保存),我希望從 getPreview() 顯示的小部件更新。 這也會更新狀態,因此當返回屏幕 1 時,列表項現在顯示“已完成”。
要求/規格:
表單數據存儲在用戶設備上的 json 中,因此提供者需要從 SharedPreferences 中提取(如果它存在),否則只是默認值。 這將更新表格 Object 中的“數據”值。
該列表的大小已知。
forms 從應用程序中的多個點更新(即“數據”),我展示了一個示例。
當表單更改時,列表顯示列表 object(比如一張卡片)中的“狀態”,並且僅更新該列表條目,而不是重建整個列表。
點擊屏幕 1 中的列表條目會轉到屏幕 2。此屏幕還可以訪問表單 Object 並顯示兩個小部件。
5.1) getForm() 中對數據的更新將更新 getPreview() 小部件。
我看過這個待辦事項示例,但有很多東西需要理解,我迷路了。
我不是在尋找任何人為我構建任何代碼,只是為了解釋一些我需要的概念,也許還有一些簡短的片段來演示它們。 例如如何擁有一個 Form 對象列表,我可以在其中更新該列表中的任何項目並在列表中顯示該更新,而無需重建所有其他項目。
在最簡單的情況下,它看起來像這樣(+一些偽代碼):
數據處理Forms
:
class Form {
Form(this.data, this.status, this.lastEditTime);
final data;
final status;
final lastEditTime;
}
final formsProvider = StateNotifierProvider<FormsNotifier, List<Form>>(
(ref) {
return FormsNotifier(ref);
},
);
class FormsNotifier extends StateNotifier<List<Form>> {
FormsNotifier(this._ref) : super([]) {
_init();
}
final Ref _ref;
_init() async {
final yourData = await _ref.read(_dbProvider).get();
state = yourData; // your list data from db
}
saveNewData(data) async {
// perform the necessary operations, save to the database and update the state.
// ...
await _ref.read(_dbProvider).set(data);
state = data;
}
}
數據庫:
class SharedPreferences {
/*
* emulation of the 'shared_preferences' package
*/
// init method
static getInstance() async {}
get() async {}
set(data) async {}
}
final _dbProvider =
Provider<SharedPreferences>((ref) => throw UnimplementedError());
主要方法
Future<void> main() async {
final sharedPreferences = await SharedPreferences.getInstance();
runApp(
ProviderScope(
overrides: [
_dbProvider.overrideWithValue(sharedPreferences),
],
child: const MyApp(),
),
);
}
用戶界面小部件:
class MyApp extends ConsumerWidget {
const MyApp({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return const Screen1();
}
}
class Screen1 extends ConsumerWidget {
const Screen1({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final List forms = ref.watch(formsProvider);
return ListView(
children: [
CardWidget(cardParameters: form[1], onPressed: () {/*go screen2*/}),
CardWidget(cardParameters: form[2], onPressed: () {/*go screen2*/}),
// ...
],
);
}
}
class Screen2 extends ConsumerWidget {
const Screen2({
Key? key,
this.form,
}) : super(key: key);
final form;
@override
Widget build(BuildContext context, WidgetRef ref) {
final newDataController = DataInputter();
return Column(
children: [
PreviewWidget(form),
FormWidget(form),
TextButton(
onPressed: () async {
await ref
.read(formsProvider.notifier)
.saveNewData(newDataController.data);
// then go to screen 1
},
child: Text('Save New Data'),
)
],
);
}
}
我盡量寫得很簡單,有些地方寫得太誇張了。 首先,您必須異步初始化數據庫。 除了上述方法,您還可以使用AsyncNotifierProvider
2.0 中的 AsyncNotifierProvider。 您可能還需要freezed
的 package 來使Form
不可變。
接下來,您需要決定 class 與路由一起“存在”的位置,以及通常如何組織路由。
這里有一篇有用的文章可以幫助您更好地了解 riverpod。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.