2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Riverpod1.0.2のAn exception was thrown while buildingエラー対処法

Posted at

An exception was thrown while buildingエラーが発生するパターンは複数あると思われますが、私が遭遇したパターンの原因と修正方法を記載します。

以下コードで実行エラーが発生しました。

view_model.dart
final speedProvider = StateProvider<int>((ref) => 5);
final stepProvider = StateNotifierProvider<StepViewModel, double>(
    (ref) => StepViewModel(0, ref));

class StepViewModel extends StateNotifier<double> {
  final Ref _ref;
  StepViewModel(double state, this._ref) : super(state) {
    _ref.read(speedProvider.notifier).addListener((_) {
      _startTimer();
    });
  }
  void _startTimer() {
    final speed = _ref.read(speedProvider);
    ....
  }
}
======== Exception caught by widgets library =======================================================
The following ProviderException was thrown building Consumer(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#1fc32):
An exception was thrown while building StateProvider<int>#bd119.

Thrown exception:
Concurrent modification during iteration.

Stack trace:
#0      StateNotifier.addListener.<anonymous closure> (package:state_notifier/state_notifier.dart:276:9)
#1      StateNotifier.addListener (package:state_notifier/state_notifier.dart:279:6)
#2      StateProvider.create (package:riverpod/src/state_provider/base.dart:88:37)
#3      ProviderElementBase._buildState (package:riverpod/src/framework/provider_base.dart:481:26)
#4      ProviderElementBase.mount (package:riverpod/src/framework/provider_base.dart:382:5)
#5      _StateReader._create (package:riverpod/src/framework/container.dart:104:11)
#6      _StateReader.getElement (package:riverpod/src/framework/container.dart:92:52)
#7      ProviderContainer.readProviderElement (package:riverpod/src/framework/container.dart:510:19)
#8      ProviderContainer.read (package:riverpod/src/framework/container.dart:298:21)
#9      ProviderElementBase.read (package:riverpod/src/framework/provider_base.dart:661:23)
#10     StepViewModel._startTimer (package:my_app/view_model/step_view_model.dart:44:24)
#11     new StepViewModel.<anonymous closure> (package:my_app/view_model/step_view_model.dart:27:7)
#12     StateNotifier.addListener (package:state_notifier/state_notifier.dart:286:17)
#13     new StepViewModel (package:my_app/view_model/step_view_model.dart:24:39)
#14     stepProvider.<anonymous closure> (package:my_app/view_model/step_view_model.dart:8:14)
#15     _NotifierProvider.create (package:riverpod/src/state_notifier_provider/base.dart:98:29)
#16     ProviderElementBase._buildState (package:riverpod/src/framework/provider_base.dart:481:26)
#17     ProviderElementBase.mount (package:riverpod/src/framework/provider_base.dart:382:5)
#18     _StateReader._create (package:riverpod/src/framework/container.dart:104:11)
#19     _StateReader.getElement (package:riverpod/src/framework/container.dart:92:52)
#20     ProviderContainer.readProviderElement (package:riverpod/src/framework/container.dart:510:19)
#21     ProviderElementBase.watch (package:riverpod/src/framework/provider_base.dart:732:32)
#22     StateNotifierProvider.create (package:riverpod/src/state_notifier_provider/base.dart:54:26)
#23     ProviderElementBase._buildState (package:riverpod/src/framework/provider_base.dart:481:26)
#24     ProviderElementBase.mount (package:riverpod/src/framework/provider_base.dart:382:5)

原因

addListener メソッドのドキュメントに

The [listener] callback will be called immediately on addition

と書いてある通り、メソッドを読んだ時にコールバックが呼ばれます。
コールバックの中で同じProviderを参照したためエラーが起きました。

修正方法1

コールバック内でProviderを使わないようにすればOKです。

  StepViewModel(double state, this._ref) : super(state) {
    _ref.read(speedProvider.notifier).addListener((state) {
      _startTimer(state);
    });
  }
  void _startTimer(int state) {
    final speed = state;
    ...
  }

もしコールバック内でProviderを使いざるを得ない場合は、修正方法2が使えます。

修正方法2

synchronously whenever [state] changes.
Set [fireImmediately] to false if you want to skip the first,
immediate execution of the [listener].

ドキュメントにある通り、 fireImmediately: false を追加すれば addListener実行時にコールバックは呼ばれなくなります。
これならコールバック内でProviderを使ってもエラーが起きません。

view_model.dart
    _ref.read(speedProvider.notifier).addListener((_) {
      _startTimer();
    }, fireImmediately: false);
2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?