Flutter: ウィジェットをキャッシュしておく

Flutter: ウィジェットをキャッシュしておく

June 5, 2024

なんとなく思いついたのでコードをメモ。

一度作成したウィジェットをキャッシュに保存しておいて、必要になったときだけウィジェットを再構築する。

次の例で行くと、3の倍数かそうでないかで表示を切り替えている。何も考えないと数字がカウントアップされるごとに SanNoBaisuWidget ウィジェットが build() メソッドで読んでいる中身のウィジェットを構築されることになるが、本当にウィジェットを再構築する必要があるのは「奇数から偶数」「偶数から奇数」に切り替わるタイミングのみである。

次のコードのようにすることで、再構築が必要なとき以外の時はキャッシュしておいたウィジェットを返すことができる。

今回の例だと SanNoBaisuWidget が返しているのは Text() だけであり軽量だが、これが複雑なウィジェットになってくればくるほどキャッシュから返すことにより効率化できることになる。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: <Widget>[
            Text(_count.toString()),
            IconButton(
              icon: const Icon(Icons.add),
              onPressed: () {
                setState(() {
                  _count++;
                });
              },
            ),
            SanNoBaisuWidget(count: _count),
          ],
        ),
      ),
    );
  }
}

class SanNoBaisuWidget extends StatefulWidget {
  const SanNoBaisuWidget({
    super.key,
    required this.count,
  });

  final int count;

  @override
  State<SanNoBaisuWidget> createState() => _SanNoBaisuWidgetState();
}

class _SanNoBaisuWidgetState extends State<SanNoBaisuWidget> {
  Widget? _cache;

  bool _isSanNoBaisu(int count) {
    return count % 3 == 0;
  }

  @override
  void didUpdateWidget(SanNoBaisuWidget oldWidget) {
    if (_isSanNoBaisu(oldWidget.count) != _isSanNoBaisu(widget.count)) {
      _cache = null;
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return _cache ??= _isSanNoBaisu(widget.count)
        ? const Text('3の倍数')
        : const Text('3の倍数ではない');
  }
}