🔥

AutoDisposeAsyncNotifierProviderFamily で無限に build メソッドが走ってしまった件

2023/07/17に公開

事象

riverpod の AutoDisposeAsyncNotifierProviderFamily の build メソッドが無限に呼び出されてしまう。

final todoListProvider =
  AutoDisposeAsyncNotifierProviderFamily<TodoListAsyncNotifier, Category, Map<String, Object>>(TodoListAsyncNotifier.new);

class TodoListAsyncNotifier extends AutoDisposeFamilyAsyncNotifier<Category, Map<String, Object>> {

  
  FutureOr<Category> build(Map<String, Object> arg) async {
    // ここの build が無限に呼び出される・・・.  
    final list = await ref.read(todoListRepositoryProvider).fetch();
    return Category(id: arg['id'] as String, name: arg['categoryName'] as String, items: list, updatedAt: arg['date'] as DateTime);
  }
}

ちなみに riverpod_generator で生成した provider もアウトでした。(最初はそれでやってました)
FutureOr でない普通の Category を返すだけなら多分発生しなかったと思う・・・。

原因

引数に DateTime.now() を渡したこと。
開発者曰く、millisecond 単位のデータを渡してしまうと(おそらく)差分が都度発生し、何回も provider が生成されてしまうっぽいです。

final date = DateTime.now();
// これだと無限に生成されてしまう...
final value = ref.watch(todoListProvider(Tuple3('aabbbb', 'category', date)));

https://github.com/rrousselGit/riverpod/issues/2745

対策

millisecond 以下は 0 にしましょう、とのことでした。
もし、millisecond 以下の値も必要であれば別途対策が必要になりそうです。

var date = DateTime.now();
// 適当に second まで値設定する.
date = DateTime(date.year, date.month, date.day, date.hour, date.minute, date.second);
final value = ref.watch(todoListProvider(Tuple3('aabbbb', 'category', date)));

Discussion