簡體   English   中英

如何在 Riverpod 的提供者中使用對象列表

[英]How to use a list of objects in a provider with Riverpod

我正在構建一個 Flutter 應用程序,並且正在努力解決整個提供者/消費者概念以及如何使用 Riverpod 解決我的問題。 我之前沒有與供應商/消費者合作過,所以我很難理解它。

下面我有一個示例圖和我試圖滿足的要求。

基本上,我有一個表格 object,我想在提供商中使用它,因為應用程序的各個地方都需要它。 object 有更新其 state 的方法。

來自 getForm() 的小部件更新數據,當數據更新時(用戶點擊保存),我希望從 getPreview() 顯示的小部件更新。 這也會更新狀態,因此當返回屏幕 1 時,列表項現在顯示“已完成”。

要求/規格:

  1. 表單數據存儲在用戶設備上的 json 中,因此提供者需要從 SharedPreferences 中提取(如果它存在),否則只是默認值。 這將更新表格 Object 中的“數據”值。

  2. 該列表的大小已知。

  3. forms 從應用程序中的多個點更新(即“數據”),我展示了一個示例。

  4. 當表單更改時,列表顯示列表 object(比如一張卡片)中的“狀態”,並且僅更新該列表條目,而不是重建整個列表。

  5. 點擊屏幕 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。

Flutter Riverpod 2.0:終極指南

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM