【Riverpod学習】同じ型のProviderを複数提供できることについて
Riverpodでは、同じ型のProviderを複数提供する場合でも、それぞれのProviderがユニークな「キー」(プロバイダ自体)として扱われるため、簡単に区別できる仕組みがあります。これにより、FlutterのProviderパッケージと異なり、同じ型の複数の状態を同時に扱うことが可能です。
具体的な仕組み:Provider自体がキーになる
Riverpodでは、各Providerがプロバイダ変数そのもので管理されるため、同じ型の状態でも異なるプロバイダ変数を使って提供すれば、区別して扱うことができます。このため、同じ型の状態を複数提供しても、どれがどのProviderに紐づくかが明確に管理されるのです。
同じ型のProviderを複数使うケース
たとえば、2つのCounterモデルをそれぞれ別々に管理したい場合を考えます。Riverpodでは、次のようにそれぞれのCounter状態を異なるProvider変数に定義することで区別が可能です。
- Counterクラスを定義
class Counter {
int value;
Counter(this.value);
}
- RiverpodのProviderを定義
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 1つ目のCounterを管理するProvider
final counterProvider1 = StateProvider((ref) => Counter(0));
// 2つ目のCounterを管理するProvider
final counterProvider2 = StateProvider((ref) => Counter(0));
counterProvider1 と counterProvider2 は同じ型(Counter)ですが、異なる変数名がそれぞれ異なるProviderを区別するための「キー」として機能します。
Riverpodでは、これらのProviderを区別して使うことができ、それぞれ独立した状態を保持します。
3. それぞれのProviderを使ってウィジェットに状態を表示する
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
child: MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Multiple Counters with Riverpod')),
body: Column(
children: [
// 1つ目のCounterの状態を表示
Consumer(
builder: (context, ref, child) {
final counter1 = ref.watch(counterProvider1).value;
return Text('Counter 1: $counter1');
},
),
// 2つ目のCounterの状態を表示
Consumer(
builder: (context, ref, child) {
final counter2 = ref.watch(counterProvider2).value;
return Text('Counter 2: $counter2');
},
),
ElevatedButton(
onPressed: () {
// 1つ目のCounterをインクリメント
context.read(counterProvider1).state.value++;
},
child: Text('Increment Counter 1'),
),
ElevatedButton(
onPressed: () {
// 2つ目のCounterをインクリメント
context.read(counterProvider2).state.value++;
},
child: Text('Increment Counter 2'),
),
],
),
),
),
);
}
}
解説
counterProvider1 と counterProvider2 はどちらも同じ型(Counter)を提供していますが、変数が異なるため、それぞれ独立して動作します。
ref.watch(counterProvider1) と ref.watch(counterProvider2) を使うことで、どちらの状態を参照するかが明確です。
ボタンを押すと、それぞれのCounterの値が個別にインクリメントされ、他方には影響を与えません。
まとめ
同じ型の複数Providerを簡単に区別できる: Providerごとに別の変数名で定義するため、同じ型でも問題なく同時に扱えます。
依存関係の明確化: それぞれのProviderがどの部分の状態を管理しているかが明確で、意図しない動作を防げます。
簡単に状態管理が可能: 複雑なウィジェットツリーを考慮せずに、同じ型の状態を異なる箇所で独立して管理できるため、コードがシンプルになります。
これにより、複数の同じ型の状態を扱いたい場合、RiverpodはProviderよりも使いやすく、柔軟に状態管理ができるツールと言えます。
Discussion