flutter_hooks/useMemoized関数
flutter_hooks/useMemoized関数(詳細は、pub.dev 参照)についての説明です。
useMemoized 関数は、
・複雑なオブジェクト(計算コストが高い値)のインスタンスをキャッシュ(メモ化)
します。そして、
・設定するキー値(依存配列)が変更された場合のみ、新しい値が再計算されます。
・それ以外の場合は、前回のキャッシュされた値が返されます。
(逆に表現すると、計算結果が異なる場合でも、キー値(依存関係)の設定が無ければ、再キャッシュはされません)
T useMemoized<T>(
T valueBuilder(
//
),
[List<Object?> keys = const <Object>[]]
)
この関数は、
・特定の計算が必要な値やオブジェクト
を生成するための
・ valueBuilder 関数を受け取ります。
また、
オプションとして
・keys リストを受け取る
ことができ、
この keys の値に基づいて
・キャッシュの有効性
が判断されます。
1.使用
(1)初回呼び出し
useMemoized は、
最初の呼び出し時に
・ valueBuilder 関数を呼び出し、
・その結果を内部的にキャッシュ
します。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class ExpensiveObject {
final int id;
final String name;
ExpensiveObject({required this.id, required this.name});
// 通常、もっと複雑な処理やリソースの消費が伴うことを想定
}
class ExpensiveWidget extends HookWidget {
@override
Widget build(BuildContext context) {
// useMemoizedを使用してExpensiveObjectインスタンスをキャッシュ
final expensiveInstance = useMemoized(() {
return ExpensiveObject(id: 1, name: 'Very Expensive');
});
return Scaffold(
appBar: AppBar(
title: Text('Use Memoized Example'),
),
body: Center(
child: Text('Object ID: ${expensiveInstance.id}, Name: ${expensiveInstance.name}'),
),
);
}
}
コードの説明)
ExpensiveObject
これはサンプルとして用意した複雑なオブジェクトを生成するクラスです。実際には、このクラスのインスタンス生成がリソースを多く消費するか、時間がかかる可能性があるため、キャッシュする価値があります。
useMemoized
ExpensiveObjectインスタンスを生成する関数を渡しています。useMemoizedはこの関数を一度呼び出し、その結果をキャッシュします。ウィジェットが再ビルドされるたびに、キーが変わらない限り同じインスタンスを返します。
このコードは、初回呼び出し時にvalueBuilder関数が実行され、結果がキャッシュされるuseMemoizedの使用方法を示しています。再ビルド時には、新たなオブジェクト生成が行われず、キャッシュからデータが取得されるため、パフォーマンスが向上します。
(2)再ビルド時
ウィジェットが再ビルドされる際に useMemoized が再度呼び出されると、keys が変更されていなければ、valueBuilder 関数を再び呼び出すことなくキャッシュされた値を返します。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class ExpensiveObject {
final int id;
final String name;
ExpensiveObject({required this.id, required this.name});
}
class ExpensiveWidget extends HookWidget {
@override
Widget build(BuildContext context) {
// useMemoizedを使用してExpensiveObjectインスタンスをキャッシュ
// キーが変わらない限り、キャッシュされた値を返す
final expensiveInstance = useMemoized(() {
return ExpensiveObject(id: 1, name: 'Very Expensive');
});
return Scaffold(
appBar: AppBar(
title: Text('Use Memoized Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Object ID: ${expensiveInstance.id}, Name: ${expensiveInstance.name}'),
RaisedButton(
child: Text('Rebuild Widget'),
onPressed: () {
// このボタンを押すとウィジェットが再ビルドされる
(context as Element).markNeedsBuild();
},
),
],
),
),
);
}
}
ウィジェットの再ビルド
RaisedButton の onPressed メソッド内で (context as Element).markNeedsBuild(); を呼び出しています。これにより、ウィジェットが強制的に再ビルドされます。
useMemoizedの動作
再ビルドが発生しても、ExpensiveObject の生成に使用されるキー(この場合は暗黙的に無し)が変更されていないため、useMemoizedはキャッシュされたインスタンスを再度返します。このため、ExpensiveObjectのコンストラクタは再ビルド時に再び呼び出されません。
この例は、ウィジェットのライフサイクル中に何度も発生する可能性のある再ビルドにおいて、計算コストが高いオブジェクトの生成を避けるためにuseMemoizedがどのように利用されるかを示しています。再ビルドが頻繁に発生しても、パフォーマンスの低下を防ぐために前回のビルドで生成された値を再利用します。
(3)キーの変更
keys が前回の呼び出しから変更されている場合は、valueBuilder が再び呼び出され、新しい値が生成されてキャッシュされます。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class ExpensiveObject {
final int id;
final String name;
ExpensiveObject({required this.id, required this.name});
}
class ExpensiveWidget extends HookWidget {
final String name; // ウィジェットのプロパティとして名前を渡す
ExpensiveWidget({Key? key, required this.name}) : super(key: key);
@override
Widget build(BuildContext context) {
// useMemoizedを使用してExpensiveObjectインスタンスをキャッシュ
// nameが変わるたびに新しいオブジェクトを生成
final expensiveInstance = useMemoized(() {
return ExpensiveObject(id: 1, name: 'Very Expensive');
}, [name]); // name をキーとして使用
return Scaffold(
appBar: AppBar(
title: Text('Use Memoized Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Object ID: ${expensiveInstance.id}, Name: ${expensiveInstance.name}'),
RaisedButton(
child: Text('Rebuild Widget'),
onPressed: () {
// このボタンを押すとウィジェットが再ビルドされる
(context as Element).markNeedsBuild();
},
),
],
),
),
);
}
}
このコードでは、nameがウィジェットのプロパティとして渡されています。これにより、nameが変更された場合にのみExpensiveObjectの新しいインスタンスが生成されます。nameが変更されない限り、useMemoizedは以前にキャッシュされたインスタンスを返し、不必要な再計算やリソース消費を避けることができます。