1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

StateNotifierProviderの初期化メソッド内でasync/awaitを使いたい ※追記あり

Last updated at Posted at 2024-02-19

2024/10/13 追記

Riverpod 2.0のAsyncNotifierProviderを使用するのがベストプラクティスっぽいです。

pubspec.yaml
dependencies:
  flutter_riverpod: ^2.5.1
  riverpod_annotation: ^2.3.5
  riverpod_generator: ^2.4.0

ますは必要なライブラリをインポートします。

dart item_list_provider.dart

part 'item_list_provider.g.dart';

@riverpod
class ItemList extends _$ItemList {
  @override
  Future<List<Item>> build() async {
      //初期化メソッドを追加
      final List<Item> initialItem = await ref.watch(hogeProvider).fetch();
        return initialItem;
    }
  };

  Future<void> addItem({required Item newItem}) async {
    final previousList = await future;
    state = AsyncData([...previousList, newItem]);
  }
}

riverpod_generatorでproviderを生成するためのファイルを作成します。

・part 〜 の部分はファイル名.g.dartとします。
・riverpod_annotation をimportしたことで@riverpodアノテーションが利用できます。
・freezedと同じような構文で _$クラス名 をextendsしてあげます
・buildメソッドをoverrideします。buildはproviderが初めて呼び出された時に実行される初期化メソッドです。(async/awaitが利用できる!)
・addItemのようにメソッドを追加できます。futureは予約変数になっており、現在のstateのFuture<List<Item>>が取得できます。awaitでList<Item>にしてあげています。
・stateはAsyncValue<List<Item>>型なのでAsyncValue()でラップしてあげています。

flutter pub run build_runner build --delete-conflicting-outputs 

ターミナルからbuild_runnerで上記コマンドを実行してあげると、dart item_list_provider.dartと同じ階層にitem_list_provider.g.dartが作成されます。

ref.watch(itemListProvider);

作成されたproviderはいつも通り上記コードで呼び出すことができます。

--- 追記ここまで ---

StateNotifierProviderはasyncを使えない…

StateNotifierの初期値にDBや内部ストレージから非同期で取得した値をセットしたい!
というケースは多々あると思います。

class FormItemList extends StateNotifier<List<Item>> {
  FormItemList(List<Item> initialState) : super(initialState);

  void set({required List<Item> itemList}) {
    state = itemList;
  }

  Future<List<Item>> addNewItem({
    required List<Item> itemList,
  }) async {

    state = [...state, ...itemList];
    return state;
  }
}

このようなStateNoriferをproviderで提供するとします。
非同期関数で取得した値を初期値として渡してあげる場合、以下のように書きたくなりますが、StateNotifierProviderの初期化メソッド内ではasync/awaitを使用できません。

final formItemProvider = StateNotifierProvider<FormItemList, List<Item>>((ref) async{
    // NG
    await initialItem = ref.watch(hogeProvider).fetch();
    return FormItemList(initialItem);
});

これと同様のことを実現するには、まずStateNotifierに初期化用のメソッドを用意してあげます。

class FormItemList extends StateNotifier<List<Item>> {
  FormItemList(List<Item> initialState) : super(initialState);

    //初期化メソッドを追加
    Future<void> initialize({required Ref ref}) async {
        // ここで非同期処理を行う
        final List<Item> initialItem = await ref.watch(hogeProvider).fetch();
        state = initialItem
    }

    // 以下略
}

StateNotifierProviderの初期化時にこのメソッドを呼んであげればOKです

final formItemProvider = StateNotifierProvider<FormItemList, List<Item>>((ref) {
   
   //空のリストでインスタンスを作成 
  final notifier = FormItemList([]);

  //初期化メソッドを呼び出す
  notifier.initialize(ref: ref);
  
  return notifier;
});

このように記述することでformItemProviderの初回呼び出し時に、非同期で取得した初期値をセットしたStateNotifierを提供することができます。
当たり前といえば当たり前な方法ですね!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?