Open4
[Flutterr] Riverpod
Riverpodとは
- Riverpod公式サイトでは「RiverpodはFlutter/Dartのリアクティブキャッシュフレームワークである」と紹介していて、これはRiverpodの状態管理パッケージとしての側面を表している
- 状態変化に反応してウィジェットを更新する仕組みが提供されており、その状態を保持するという意味
- 状態の保持に関してはウィジェットのライフサイクルに左右されず、破棄のタイミングをコントロールすることができる
- 状態管理パッケージとしての側面以外にも、クラスの依存関係を解決するための仕組みを提供している(DI)
Riverpodの主要なクラス
主要なクラス
1. Provider
2. RefとWidgetRef
3. ConsumerWidget
それぞれの役割と関係性
- Providerが状態をキャッシュし、RefやWidgetRefを介して状態を提供する
- ConsumerWidgetはウィジェットのサブクラスである
- ConsumerWidgetのbuildメソッドの引数にはWidgetRefが渡され、それを介して状態を取得し、ウィジェットを構築する
- Providerの持つ状態が変化すると、buildメソッドが再度呼び出される
実装サンプル
状態を保持するNotifierと提供するNotifierProviderの実装
int型の数値を状態として提供し、かつその値を変更可能なProviderを実装する
class CounterNotifier extends Notifier<int>{
int build() => 0;
void increment(){
state = state + 1;
}
}
final counterNotifierProvider = NotifierProvider<CounterNotifier, int>((){
return CounterNotifier();
});
- 状態を変更可能なProviderはNotifierというクラスを使う
- カウンタの値を保持し、インクリメントするCounterNotifierというクラス
- Notifierクラスは自分の状態をstateプロパティに保持している
- Notifier<int>と渡している型パラメーターが状態の型になる
- CounterNotifierクラスをNotifierProviderで提供する
表示するためのWidgetの実装
class MyHomePage extends ConsumerWidget{
const MyHomePage({super.key,required this.title});
final String title;
Widget build(BuildContext context, WidgetRef ref){
final counter = ref.watch(counterNotifierProvider);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
ref.read(counterNotifierProvider.notifier).increment();
},
tooltip: 'Increment',
child: const Icon(Icons.add),
)
);
}
}
- WidgetRefのwatchメソッドを使って状態を監視した場合、状態が変化するとbuildメソッドが再び呼び出される
Riverpodの関連パッケージ
Riverpodは以下の3つのパッケージで構成されている
基本機能を提供するパッケージ
- riverpod
- flutter_riverpod(flutterでは通常これを使う)
- hooks_riverpod
Providerのコードを生成するパッケージ
- riverpod_generator(コード生成)
- riverpod_annotation(コード生成のためのアノテーション)
※ build_runnerパッケージも必要になる
// コード生成を利用しない場合
final greetProvider = Provider((ref){
return 'Hello, Flutter!';
});
// コード生成を利用する場合
String greet(GreetRef ref){
return 'Hello Flutter!';
}
- Providerに関するコードの記述する際の意思決定が減る
- Providerへ渡すパラメータの制限がなくなる
- Providerの変更がホットリロードできる
静的解析を行うパッケージ
- riverpod_lint
※ custom_lintも必要
関連パッケージまとめ
pubspec.yaml
dependencies:
flutter_riverpod:
riverpod_annotation:
dev_dependencies:
riverpod_generator:
build_runner:
custom_lint:
riverpod_lint:
コマンドラインから導入する場合
$ flutter pub add flutter_riverpod riverpod_annotation
$ flutter pub add --dev riverpod_generator build_runner custom_lint riverpod_lint
コードの生成例
part 'main.g.dart';
class CounterNotifier extends _$ConterNotifier{
int build() => 0;
void increment(){
state = state + 1;
}
}
- @riverpodアノテーションを付与する
- _$ + クラス名の型を継承する
- 初期値をbuildlメソッドで返す
実装が完了したらコード生成のために、以下のコマンドを実行
$ flutter packages pub run build_runner build
ProviderScope
- プロバイダが持つ状態(state)やロジック(logic)をアプリ全体でアクセス可能にするもの
- アプリケーションのルートにプロバイダのスコープを設定し、そのスコープ内で定義された全てのプロバイダの状態を管理することができ、これにより、状態の共有や更新がアプリケーションのどの部分からでも行えるようになる
ProviderScopeの使い方
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}