flutterの状態管理方法は色々あるが、 rxにある程度慣れているという理由で私はBlocパターンを好んでいた。 ただriverpodが業界標準ぽいので使用方法や雰囲気のメモをしておく。 Provider + BLoc を作ってみたが使うかは検討
Provider
中心的存在はこのProvider
シングルトン的役割を果たしてグローバルに変数をおいて各ページから利用する。
プロバイダを利用するには、Flutter アプリのルート(root)に ProviderScope を置く必要がある。
void main() {
runApp(ProviderScope(child: MyApp()));
}
デフォルトのステート管理wigetとの対応
flutterで標準
ステート管理をするwiget : StatefullWidget
(初期化処理あり)
ステート管理をしないwiget : StatelessWidget + State
(初期化処理なし)
Providerを使う場合
StatelessWidget の代わりに ConsumerWidget
StatefullWiget の代わりに : ConsumerStatefulWidget+ ConsumerState
※hooksを使う場合にも対応があるがそれは今回はスルー
ConsumerWidgetでProviderパターンを利用する例(一般的なの利用方法)
class Counter extends StateNotifier<int> {
final Ref ref;
Counter(this.ref) : super(0);
void increment() {
state++;
}
}
final counterProvider =
StateNotifierProvider.autoDispose<Counter, int>((ref) => Counter(ref));
class CounterHome extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(counterProvider);
final counter = ref.watch(counterProvider.notifier);
void onClicked() {
counter.increment();
}
return Container(
child: Column(
children: [
const SizedBox(height: 10),
Center(child: Text('StateNotifierProvider : $state')),
ElevatedButton(onPressed: onClicked, child: const Text("increment")),
],
));
}
}
Flutterには値を変更を通知するクラスとしてValueNotifier
が存在していて、それをProviderで使う場合StateNotifier
を使うと理解しておけばよいぽい。
Provier + BLOCの例
Flutterの値通知の標準があるので、それを踏まえてStateNotifierを使ってProviderを利用するのが普通ぽいのだが、これをStreamに置き換えてRxdartを使って利用する場合(rxdartを使う)
final counterBlocProvider = Provider((_) => CounterBloc(100));
class CounterBloc {
final BehaviorSubject<int> countSubject;
Stream<int> get countStream => countSubject.stream;
final StreamProvider<int> countStreamProvider;
int get count => countSubject.value;
CounterBloc(int _count)
: countSubject = BehaviorSubject<int>.seeded(_count),
countStreamProvider = StreamProvider<int>((ref) {
return ref.watch(counterBlocProvider).countStream;
});
void increment() {
countSubject.value++;
}
void clear() {
countSubject.sink.add(0);
}
void dispose() {
countSubject.close();
}
}
class CounterHome extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final countBloc = ref.watch(counterBlocProvider);
AsyncValue<int> countBlocStream = ref.watch(countBloc.countStreamProvider);
void onClicked() {
countBloc.increment();
}
void onClear() {
countBloc.clear();
}
return Container(
child: Column(
children: [
countBlocStream.when(
loading: () => const CircularProgressIndicator(),
error: ((error, stackTrace) => const Text('Oops')),
data: (count) => Center(child: Text('bloc : $count'))),
ElevatedButton(
onPressed: onClicked, child: const Text("increment")),
const SizedBox(
height: 10,
),
ElevatedButton(onPressed: onClear, child: const Text("reset")),
],
));
}
}
郷に入っては郷に従え
というが反して、
flutter特有のNotifier(ValueNotifier, StateNotifier)を使った値通知を利用したくないなぁと思って誰も使わなそうなProvider + BLOCパターンの状態管理を作ってみた。disposeの管理や自己参照周りが怪しいのでさらに調査必要である。