Open6

Riverpodまとめ

futaba3futaba3

Riverpodのプロバイダ修飾子
.autoDispose → プロバイダの監視が終わったタイミングでプロバイダに自動でステートを破棄させることができるようになる。メモリリークを未然に防ぐことができる。
.family → プロバイダ外部の値を用いてプロバイダを作成できるようになる。ListViewの要素に画像などの表示するデータを渡したいとき、詳細に遷移した際にIDを渡したいときなどに使う。

https://zenn.dev/riscait/books/flutter-riverpod-practical-introduction/viewer/auto-dispose

状態の破棄 .autoDispose / ref.invalidate() / ref.refresh()

.watchまたは.listenでは状態を監視しているので、不要になったら破棄すべき

不要になった状態を自動的に破棄するautoDispose
任意のタイミングで状態を破棄させる.invalidate() と .refresh() がある

破棄されたあと、状態が必要になったら再度生成される

.autoDispose

監視しているrefがなくなったとき、管理する状態とNotifierを破棄する
riverpod_generatorを使うとデフォルトで有効になる = 使わない場合は明示的につける必要がある

autoDisposeをつけないケース

  • 常にアプリの起動中存在し続けるべきグローバルな状態: アプリケーション全体で共有される設定情報や認証状態など、常に保持しておく必要があるデータを持つプロバイダ
  • キャッシュとして利用するプロバイダ: 一度取得したデータを再利用したい場合、autoDispose を付けずにキャッシュとしてプロバイダを保持することがあります。
  • 意図的に状態を保持したい場合: 特定の画面から離れても状態を保持しておきたい場合など、開発者の意図として破棄したくないプロバイダ。
    ref.readは状態を監視していないので、ref.readでしか使われないproviderはreadするたびにproviderが生成・破棄されるため注意

.invalidate()

管理する状態を破棄する(Notifierは破棄されない)

.refresh()

.invalidate()ref.read を連続で呼び出したときと同じ挙動をする

futaba3futaba3

riverpod providerの.futureはいつ使うのか
ex) final userId = await ref.watch(userIdProvider.future);

非同期処理の結果を即座に取得したい場合

非同期処理が完了するまで待ちたい場合に適しています。
例: Firestore からデータを取得して次の処理を行う場合。
final userId = await ref.watch(userIdProvider.future);

エラーハンドリングを簡潔に行いたい場合

try-catch を使ってエラーを処理できます。
try {
final userId = await ref.watch(userIdProvider.future);
print('User ID: $userId');
} catch (e) {
print('Error: $e');
}

.value を使うべき場合
.value を使うのは、非同期処理の状態(loading や error)を UI に反映させたい場合です。
final userIdState = ref.watch(userIdProvider);
return userIdState.when(
data: (userId) => Text('User ID: $userId'),
loading: () => CircularProgressIndicator(),
error: (err, stack) => Text('Error: $err'),
);

futaba3futaba3

Riverpod
.readと.watch何が違うの

.read
ユーザーの操作によってトリガーされる関数内でよく使用される
しかし、以下のような記述があり、.readはリアクティブでないため、できるだけ使用しないことが推奨されている。.readは.watchか.listenを使用すると問題が発生する場合のために存在するので、可能であれば、.watchを利用するのが適切。

Using ref.read should be avoided as much as possible because it is not reactive.
It exists for cases where using watch or listen would cause issues. If you can, it is almost always better to use watch/listen, especially watch.

buildメソッドの中では使わない

https://riverpod.dev/docs/concepts/reading

ref.watchとref.readの違い
ref.watch():

プロバイダーの状態を監視しており、状態が変わるたびにウィジェットやクラスが再ビルドされます。
主にUI(ウィジェット)の中で使用され、リアクティブに状態を反映させたいときに便利です。
使う場面:
UIが状態に応じて動的に更新される必要があるとき。
例えば、APIの結果やユーザー入力に応じて画面を変えたい場合。
ref.read():

プロバイダーの値を一度だけ読み取ります。その後の状態変化を監視しません。
主に非同期処理やイベントハンドラの中で使います。リアクティブに再ビルドされる必要がない場面に適しています。

使う場面:
一度だけ状態を取得したい場合や、更新をトリガーしたい場合。
例えば、ボタンを押したときにAPIを叩くような場面で使います。
問題がref.watchからref.readに変更することで解決した理由
ref.watchは、プロバイダーが更新されるたびにそのウィジェットやクラスを再ビルドしようとします。そのため、非同期処理の結果などを監視したいわけではない場合、無駄にリビルドが発生し、パフォーマンスやロジックに影響が出る可能性があります。

riverpodのref.readはBuildメソッド内では使ってはならない・Stateのライフサイクルメソッド内でも使ってはならない

watch メソッドは ElevatedButton の onPressed 内など、非同期的な場面で呼び出さないでください。 また initState を始め、State のライフサイクルメソッド内での使用も避けてください。
これらの場合は代わりに ref.read を使用してください。

https://riverpod.dev/ja/docs/concepts/reading#重要-refread-は-build-メソッドの中で使わない