Reading a provider
このガイドを読む前に、まずProvidersをお読みください。
このガイドでは、プロバイダを使う方法について説明します。
プロバイダのreadする方法は複数あり、基準によって少しずつ異なります。
長くなりましたが、ここでは、プロバイダをreadするときに何を使うかを決めるための判断グラフを紹介します。
次に、個々のケースを見て、その仕組みを紹介します。
このガイドでは、以下のプロバイダーを検討します。
何をreadするかを決める#
listenしたいプロバイダによっては、listen可能な値が複数ある場合があります。
例として、次のようなStreamProviderを考えてみましょう。
このuserProviderをreadするときには
userProvider自身をlistenすることで、現在の状態を同期的にreadする:userProvider.streamをlistenして、関連する[Stream]を取得する:userProvider.lastをlistenして、emitされた最新の値で解決する[Future]を取得する:
詳細は、APIリファレンスを参照して、各プロバイダのドキュメントを参照してください。
Widgetの中でプロバイダを使う#
このセクションでは、FlutterのWidgetがどのようにプロバイダと連携するかを見ていきます。
ConsumerWidget#
ConsumerWidget は、StatelessWidget に似たウィジェットのベースクラスですが、プロバイダをlistenすることができます。
counterProviderの値がどのようにwatchという関数で取得されているかに注目してください。
この関数は、ConsumerWidgetがプロバイダをlistenし、値が変更されたときに再構築するためのものです。
caution
ConsumerWidgetの引数として渡されるwatchメソッドは、
onPressedやElevatedButtonの内部のように、非同期的に呼び出されるべきではありません。
ユーザーイベントに応じてプロバイダをreadする必要がある場合は、context.read(myProvider)を参照してください。
Consumer#
ConsumerはConsumerWidgetであり、データを使用する必要のあるWidgetのみを再構築することで、
アプリケーションのパフォーマンスを最適化するために使用することができます。
例えば、前に見たConsumerWidgetのコードスニペットを更新して、
カウンターが変更されたときにTextだけを再構築するようにします。
この例では、UIがcounterProviderをlistenし、カウンターが変更されるとTextをリビルドします(そのTextのみ)。
useProvider (hooks_riverpod のみ)#
flutter_hooks/hooks_riverpodを使用している場合、ConsumerWidgetの代わりに[ref.watch()]を使用することができます。
これはflutter_hooksとRiverpodの両方を併用したい場合に便利です。
この構文は、ConsumerWidgetではサポートされていない機能もサポートしています。[select] です。
この構文を使うと、isAbove5変数が変化した場合に のみ 、Widgetが再構築されます。
つまり、カウンターが 1 から 2 に変更されても、 Widgetが再構築されることはありません 。
context.read(myProvider)#
Consumerと[ref.watch]では、プロバイダを listen する方法を見てきました。
しかし、状況によっては、そのオブジェクトをlistenする価値がないこともあります。
例えば、ElevatedButtonのonPressedのためだけにオブジェクトが必要な場合があります。
私たちは、[ref.watch]/Consumerを使用することができます。
しかし、それでは効率が悪いでしょう。
listenされたプロバイダによっては、カウンタが実際にはElevatedButtonの構築に使用されていなくても、
カウンタが変更されたときにElevatedButtonが再構築されることがあります。
そこで、context.read(myProvider)が解決策となります。
これを使うことで、以前のコードをリファクタリングします。
こうすることで、ボタンをクリックしても、カウンターは増えていきます。
しかし、無駄なリビルドを避けるために、プロバイダをlistenしなくなっています。
context.readメソッドが見当たらないのですが、これはなぜでしょうか?
もし、context.readが表示されない場合は、正しいパッケージをインポートしていない可能性があります。
このメソッドを表示するには、package:flutter_riverpodまたはpackage:hooks_riverpodのいずれかをインポートする必要があります。
info
listenするプロバイダによては、この作業が必要ない場合もあります。 例えば、StateNotifierProviderは、StateNotifierの状態をlistenせずに取得する方法を内蔵しています。
caution
Widget の build メソッド内での context.read の呼び出しを避けてください。
リビルドを最適化したい場合は、代わりにProviderでlistenされた値を抽出します。
ProviderListener#
プロバイダの変更後にルートをプッシュしたり、ダイアログを表示したりするために、
Widgetツリーが必要になる場合があります。
このような動作は、ProviderListener Widgetを使用して実装されます。
これにより、カウンターが5に達したときにダイアログが表示されます。
プロバイダの中で別のプロバイダをreadする#
プロバイダーを作る際によくあるのが、他のオブジェクトからオブジェクトを作りたいというケースです。
例えば、UserRepositoryからUserControllerを作成したい場合、
両方のオブジェクトは別のプロバイダで公開されます。
このようなシナリオは、プロバイダがパラメータとして受け取る ref オブジェクトを使用することで可能になります。
Combining Providers(プロバイダーの組み合わせ)のガイドには、
以下のような情報が掲載されていますので、ぜひご覧ください。
- 時間の経過とともに変化する値からオブジェクトを作成するとどうなるか?
- いくつかのグッドプラクティス
Dartのみの場合のプロバイダ外のプロバイダのread#
場合によっては、Flutterに依存していないパッケージのプロバイダをreadしたいこともあるでしょう。
よくあるケースは、Widgetとは関係のないクラスをテストする場合です。
このような状況では、プロバイダを操作するための低レベルのユーティリティであるProviderContainerを使用することができます。
次のスニペットは、Flutterを使わずにテストでプロバイダをreadする方法を示しています。
danger
ProviderContainerのインスタンスをテスト間で再利用しないでください。 これにより、テストケース間でプロバイダの状態が適切にリセットされるようになります。