🐕

【Flutter Widget of the Week #30】ValueListenableBuilderを使ってみた

2022/12/05に公開

はじめに

Flutter Widget of the Week #30 ValueListenableBuilder についてまとめましたので、紹介します。
https://youtu.be/s-ZG-jS5QHQ

ValueListenableBuilder

たくさんデータがあり、それらが変わる可能性がある場合、データが変わるたびに複数の場所を手動で更新するのはすごく手間です。そんなときに、ValueListenableBuilder が効果的です。データが追加されたときや変更されたとき、自動的に画面の再構築をしてくれるので、手間が省けます。
では、さっそくサンプルを動かして使い方を見てみましょう。

ValueListenableBuilder サンプルコード

ValueListenableBuilder サンプル実行画面
ValueListenableBuilder サンプル実行画面

基本のサンプルコード全体

class ValueListenableBuilderSample extends StatefulWidget {
  const ValueListenableBuilderSample({super.key, required this.title});
  final String title;

  
  State<ValueListenableBuilderSample> createState() =>
      _ValueListenableBuilderSampleState();
}

class _ValueListenableBuilderSampleState
    extends State<ValueListenableBuilderSample> {
  final ValueNotifier<int> _counter = ValueNotifier<int>(0);
  final Widget goodJob = const Text('Good job!');
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            ValueListenableBuilder<int>(
              builder: (BuildContext context, int value, Widget? child) {
                return Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    Text('$value'),
                    child!,
                  ],
                );
              },
              valueListenable: _counter,
              child: goodJob,
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.plus_one),
        onPressed: () => _counter.value += 1,
      ),
    );
  }
}

使い方としては、
状態管理したい部分を ValueListenableBuilder でラップします。
次に監視する値を valueListenable に設定します。

final ValueNotifier<int> _counter = ValueNotifier<int>(0);
     ・・・
ValueListenableBuilder<int>(
  builder: (BuildContext context, int value, Widget? child) {
    ・・・
  },
  valueListenable: _counter,  // 監視する値←この値が変化したらbuilderを更新する
  ・・・
)

それにより、valueListenable に設定した値に変化があったとき、builder内を更新します。
サンプルでは、floatingActionButton でボタンをタップすると _counter の値が変化するので、そのたびにbuilder内の Row widget が更新されるようになります。

ValueListenableBuilder<int>(
  builder: (BuildContext context, int value, Widget? child) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Text('$value'),
        child!,
      ],
    );
  },
  valueListenable: _counter,
  child: goodJob,
)

ここで builder の引数にある child は ValueListenableBuilder の child で指定している goodJob が返されます。なお、child に設定した widget は valueListenable に依存しません。
基本的な使い方としては以上となり、ValueListenableBuilder を使うことで不要な build が走らなくなるので、処理負荷を減らせます。

ValueListenableBuilder のプロパティについて

ValueListenableBuilder にはいくつかプロパティがあるので、紹介します。
Tには intやStringなどの型が入ります。

(new) ValueListenableBuilder<T> ValueListenableBuilder({
  Key? key,
  required ValueListenable<T> valueListenable,
  required Widget Function(BuildContext, T, Widget?) builder,
  Widget? child,
})

①valueListenable

構築するために依存する値を指定する
型は ValueListenable<T> 型

②builder

valueListenable の値に応じて再構築する widget を設定する
型は Function(BuildContext, T, Widget?) 型

最後に

今回は ValueListenableBuilder を紹介しました。シンプルに状態管理ができるので使い方は簡単ですが、最近は Provider や Riverpod などを使って状態管理を行う場合が多いので、あまり使うことはないかと思います。ですが、少しでも気になった方は是非使ってみてください。
次は #31 Draggable です。またお会いしましょう。

参考記事

https://api.flutter.dev/flutter/widgets/ValueListenableBuilder-class.html

Discussion