概要
hooksは、Riverpodを開発したRemi Rousselet氏によって開発されています。基本的には1画面でシンプルなアプリに向いています。
最も短いコードでソースを記述することが可能です。
HookWidgetを継承したクラスを宣言する。
useStateで、変数の値の保持、値の更新処理を行う。
useEffectで、変数の値が更新された時に、関数を実行できる。(ただし配列やオブジェクトは、要素の追加ではなく、新規に作成する)
注意事項(個人的な雑感)
扱える変数の型に制限があるようです。少なくともDateTime型は扱えなかった。(オブジェクト?要調査)
多国語対応する場合には、StatefulWidgetを多重に使ったりするので、Hooksではちょっと対応困難かなぁ。
個人的には、あんまりお勧めしません。useStateとか面倒だけど、普通にStatefulWidgetを使いましょう!!
パッケージのインストール
flutter pub add flutter_hooks
お約束のHello world!
flutter create hooks_test で吐き出されたサンプルソースをHookWidgetで書き直しました。
Stateクラスが不要であり、build関数の中にint型変数countを宣言しています。(宣言はちょっと特殊な書式になってます。)
値の更新は、ボタンの onPressed: を関数化して、直接「count.value++;」簡単ですね。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends HookWidget {
@override
Widget build(BuildContext context) {
final count = useState<int>(0);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('Hello hooks world!'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text(
count.value.toString(),
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
count.value++;
},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
useStateの活用例
前述のサンプルソースで示したように、build関数内でさまざまなローカル変数のようなものが使えます。
変数の宣言文は独特の書式になっています。
const count = useState<int>(0);
const isOpen = useState<bool>(false);
const user = useState<User?>(null); // 初期値が存在しない場合はこのように?を用いることでnullを定義可能
値の更新も、build関数の中で、以下のように簡単に記述できます。
値を更新すると、画面も自動的に再描画されます。
count.value++; // 年齢をインクリメント
isOpen.value = true; // isOpenをtrueに更新
user.value = User(id: 'test', ...); // 新しいユーザーに更新
user.value = null; // nullに更新
useEffectの活用例と注意事項
useEffectは、値が更新された時に関数を実行することが可能です。
useEffect では第一引数に、実行したい関数を記載します。
第 2 引数には「変更を検知したい変数」を配列内に列挙します。
final page = useState<int>(0);
useEffect(() {
getUser(page);
return null;
}, [page]);
updatePage() => {
page.value++;
}
...(中略)
return IconButton(
icon: const Icon(Icons.navigate_next),
onPressed: updatePage);
ただし、配列やオブジェクトの場合は、要素を追加するだけではuseEffectは稼働しません。新しい配列に差し替えるような動きにする必要があります。ここだけ注意ですね。
final list = useState<List<String>>([]);
useEffect(() {
getUser();
return null;
}, [list]);
updatePage() => {
// 新しい配列を生成して設定
final newList = [...list, "new item"];
list.value = newList;
}
...
Riverpodと併用可能
flutter公式は、Riverpodを正当なWidgetと認めていますが、Hooksについては、StatefulWidgetを使うことを推奨しており、現時点においても推奨されてはいません。(禁止はされていない)しかし、非常に短いコードで記述出来る魅力は侮れないですよね!
RiverpodとHooksを併用する場合は、下記パッケージをaddします。
flutter pub add hooks_riverpod
アプリ全体で共有したいデータをRiverpodで管理して、build関数内で使用するローカル変数をHooksのuseStateで宣言するような使い方になります。
サンプルソースは後日、追記します。