本題から外れるため、詳細には説明しませんが、 flutter_hooks
を導入するといくつかの便利な機能が使用可能になります。
ここに一部の機能を書き連ねます。
共通の使い方
flutter_hooks
に共通する useXxx()
というメソッドは、 StatefullWidget
や StatelessWidget
では使用できません。
ではどうしたら使えるかというと、 HookWidget
[1] または HookBuilder
[2] を使います。
HookXxx の違い
- HookWidget
build
メソッドでhooks
が使用できる。StatefullWidget
やStatelessWidget
の代わりに使う。 - HookBuilder
Consumer
Widgetと同じく、囲った以下のWidgetのみ hooks が利用できるようになる。 - StatefulHookWidget
hooks
が使用できるStatefullWidget
[3]。
useProvider(provider)
Riverpodの解説本なので一番に挙げました。
provider
を読み取り、その変化によってWidgetを再構築させます。
ConsumerWidget
の watch
と比較した、 useProvider
の利点は以下の通りです。
-
build
メソッドの引数にScopedReader watch
を追加する必要がない - 再構築を抑えることができる
select
構文が使用できる
それ以外は watch
とほぼ同じように使えます。
useEffect()
HookWidgetでは StatefullWidgetの initState()
が使用できません。
単に利用できなくなるのであれば困りますが、 useXxx
メソッドで代替できます。
Widget build(BuildContext context) {
useEffect(() {
// 第二引数に指定した要素に変化がなければ再実行されないため、
// `StatefullWidget` の `initState` のように初回ビルドのみ実行させたい処理を指定できる
fetchData();
// 戻り値として関数を返す。この関数は dispose されたときに実行されるため、
// `StatefullWidget` の `onDispose` と同じように利用できる
// 特に必要ない場合は `null` を返せばOK
return null;
// このListで指定した要素が更新されたとき、 `useEffect` が再実行される。つまり、空Listを指定しておけば再実行されない。
}, const []);
}
useTextEditingControllerなどなど
TextEditingController[4] を生成できる。
dispose
などの取り回しが不要で1行で簡潔に利用することができます。
Widget build(BuildContext context) {
final textEditingController = useTextEditingController(text: 'initial text');
return TextField(
controller: textEditingController,
...
)
}
他にも、一例ですが以下のように豊富な関数が用意されています。
useAnimation
useAnimationController
useFocusNode
usePageController
useScrollController
useSingleTickerProvider
useStreamController
useTabController
useMemoized
インスタンスをキャッシュし、Widgetが再構築されても、キャッシュに保存したインスタンスを使用してくれます。
// `useMemoized` を使用すれば、Widgetが再構築されても、nowの値は変わりません
final now = useMemoized(() => DateTime.now());
後述の useFuture
/ useStream
と併用することも多いです。
useFuture
Flutterの FutureBuilder
を使用するとネストが発生してしまいますが、 useFuture
を使うことでネストを浅くすることができます。
FutureBuilder
で書いた場合
Widget build(BuildContext context) {
return FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('Errorが発生しました');
}
if (snapshot.hasData && snapshot.data != null) {
final packageInfo = snapshot.data!;
return Text('${packageInfo.appName}');
}
return const Text('loading');
},
);
}
useFuture
で書いた場合
Widget build(BuildContext context) {
// useMemoizedを使用することで、結果がキャッシュされてWidget再構築時に再処理されなくなる
final future = useMemoized(PackageInfo.fromPlatform);
final snapshot = useFuture(future, initialData: null);
if (snapshot.hasError) {
return const Text('Errorが発生しました');
}
if (snapshot.hasData && snapshot.data != null) {
final packageInfo = snapshot.data!;
return Text('${packageInfo.appName}');
}
return const Text('loading');
}
useStream
useStream
は、使用する値がFuture
ではなくStream
であるという事実を除いて、 useFuture
と使用方法は同じです。
参考リンク
flutter_hooks
-
https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/HookWidget-class.html ↩︎
-
https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/HookBuilder-class.html ↩︎
-
https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/StatefulHookWidget-class.html ↩︎
-
https://api.flutter.dev/flutter/widgets/TextEditingController-class.html ↩︎