Flutter Riverpodについて 

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パターンを利用する例(一般的なの利用方法)

counter_provider.dart
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));
main.dart
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を使う)

counter_bloc.dart
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();
  }
}
main.dart
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_provider_block_shot

郷に入っては郷に従え というが反して、 flutter特有のNotifier(ValueNotifier, StateNotifier)を使った値通知を利用したくないなぁと思って誰も使わなそうなProvider + BLOCパターンの状態管理を作ってみた。disposeの管理や自己参照周りが怪しいのでさらに調査必要である。


References