【Flutter/Dart/Riverpod】ConsumerWidget/ConsumerStatefulWidgetの使い方と違い

【Flutter/Dart/Riverpod】ConsumerWidget/ConsumerStatefulWidgetの使い方と違い

この記事からわかること

  • Flutter/Dart状態管理を行うRiverpodとは?
  • ConsumeConsumerWidgetProviderScopeConsumerStatefulWidget使い方違い

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

Consumer/ConsumerWidget/ConsumerStatefulWidgetの違い

Riverpodでは登録したProviderへアクセスするためにWidgetRef型を介する必要があり、ここからProviderの値を「監視(watch)」・「読み取り(read)」が行えるようになります。ただWidgetRef型はどこからでも参照できるわけではなく、参照できる箇所を明示的に作り出す必要があります。

final count = ref.watch(counterProvider);
final count = ref.read(counterProvider);

RiverpodではConsumer/ConsumerWidget/ConsumerStatefulWidgetの3つがWidgetRef型を参照できるように用意されており、それぞれに使い方とメリットが異なります。

Consumer

ConsumerUIの一部でのみProviderを参照したい場合に使用します。一部のみに制限できるので無駄な範囲に再描画を走らせることなく活用することができるのが大きなメリットです。また局所的な変更で済むので既存でStatelessWidgetStatefulWidgetを使用していた場合でも簡単に導入することが可能になっています。

Consumer(
  builder: (context, ref, child) {
    final count = ref.watch(counterProvider);
    return Text('Count: $count');
  },
)

さらに特徴として引数child再描画したくないUIを任意のWidget型で渡すことが可能です。ここで指定したWidgetは引数builderWidget Function(BuildContext context, WidgetRef ref, Widget? child)内のWidget? childから参照することが可能です。

Consumer(
  builder: (context, ref, child) {
    final count = ref.watch(counterProvider);
    return Column(
      children: [
        Text('Count: $count'),
        // 再描画対象ではないWidgetを使用
        if (child != null) child,
      ],
    );
  },
  // 再描画したくないWidgetを指定
  child: const Text('このテキストは再ビルドされません'),
)

ConsumerWidget

ConsumerWidgetWidget単位でProviderを参照したい場合に使用します。Widget単位にはなるので再描画される際もWidget単位になるので注意が必要です。ただStatelessWidgetのように使用することが可能で、Widget build(BuildContext context, WidgetRef ref)の引数からWidgetRef型を参照することが可能です。

class CounterView extends ConsumerWidget {
  
  
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('Counter with Riverpod')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Counter Value', style: TextStyle(fontSize: 20)),
            const SizedBox(height: 10),

            Text(
              '$count',
              style: const TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
            ),

            const SizedBox(height: 20),

            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // デクリメントボタン
                DecrementButton(),
                const SizedBox(width: 20),
                // インクリメントボタン
                IncrementButton(),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

ConsumerStatefulWidget

ConsumerStatefulWidgetWidget単位でProviderを参照したい場合に使用します。ConsumerWidgetとの違いはStatefulWidgetベースなのでinitState、dispose、setStateなどのライフサイクルメソッドが使えることです。

使用方法はStatefulWidgetと同じような感じでWidgetRefthis.refで使用することが可能になっています。

class CounterView extends ConsumerStatefulWidget {
  @override
  ConsumerState<CounterView> createState() => _CounterViewState();
}

class _CounterViewState extends ConsumerState<CounterView> {
  
  @override
  void initState() {
    super.initState();
    final count = ref.read(counterProvider);
    print('初期カウント: $count');
  }

  @override
  Widget build(BuildContext context) {
    final count = ref.watch(counterProvider);
    return Text('Count: $count');
  }
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article