
今回は、Flutter Hooks の利点と、主に 2 つのフックである useState と useEffect について見ていきます。
まず最初に、UI を再構築することができる、ネイティブの Flutter の setState についてお話ししたいと思います。
setState
はウィジェットを再構築する関数で、UI の変化を表示するために Stateful ウィジェットで使用されます。

- このGIFを見てみましょう。タイマーがバーの
長さと位置を常にチェックして、setState
を
使って UI を再構築しています。 - しかし、
setState
は他のウィジェットも再構築
してしまいます。
Widget buildTextWithImages(String text)
{
print("loop");
/////////////////////////////////
110 I/flutter ( 3596): loop
- まず最初に、タイマーによって他のウィジェットが再構築されるのを防ぐにはどうすればよいでしょうか?
- 他のウィジェットが再構築されるのを防ぐために、
ValueNotifier
を使います。


late double timerValue
をlate ValueNotifier<double> timerValueNotifier
に変更します。

- ここでは初期化時に、
timerValueNotifier =
ValueNotifier<double>(1.0)
と代入して
います。

ValueNotifier
の値にアクセスするには、timerValueNotifier.value
を使います。

- ウィジェット内で
timerValueNotifier
を使うには、ValueListenableBuilder
を使って、ノーティファイアを監視し、
その値に応じて UI を構築する必要があります。
ValueListenableBuilder
でラップされ
たウィジェットのみが値の変化に応じて
再構築され、ウィジェットツリー全体や
親ウィジェットは再構築されません。これに
対してsetState
はStatefulWidget
全体
を再構築するため、関係のない子ウィジェット
まで影響を受ける可能性があります。
- これらすべてが Flutter Hooks とどう関係しているのでしょうか?

- Spotify の UI を見てみましょう。ここに
ある各ボタンは、それぞれの状態を更新し、
アイコンを変更しています。
- つまり、これを実現しようとすると、
コード内に複数のValueListenableBuilder
とValueNotifier
を使う必要があり、結果として
コードがごちゃごちゃになってしまいます。
- これを防ぐために、
flutter_hooks
というパッケージを使うことができます。このパッケージには、便利なフックであるuseState
が用意されています。

useState
の中身を見てみると、内部でValueNotifier
が使われていることが分かります。

useState
を使うには、型と初期値を
指定する必要があります。

useState
の変数はValueNotifier
と
同じように使い、.value
プロパティで
値にアクセスします。


- UI では
.value
プロパティを直接使う
ことができます。
- 補足:カスタムフックのコントローラーを
使っているため、meanings.value
をmeanings
としてエクスポートする必要が
あります
useState
を使うことで、ValueListenableBuilder
やValueNotifier
を使う必要がなくなり、不必要なボイラープレートを避けることができます。
- もうひとつ非常に便利なフックが
useEffect
で、これは Flutter のネイティブなinitState
の代わりとして使うことができます。


initState
と同様に、useEffect
は依存配列を空にすると、初回読み込み時に初期化処理を行うのに役立ちます。
final count = useState(0);
// 'count.value' が変わるたびに実行される副作用
useEffect(() {
// このコードは初回レンダー時と count.value が変わるたびに実行される
print('Count changed: ${count.value}');
// ここで API コールなどの他の副作用を行うこともできる
// オプションのクリーンアップ関数(今回は不要)
return null;
}, [count.value]); // 依存配列に count.value を含める
- しかし、
initState
と違って、useEffect
には依存配列があり、それによってプロジェクト内で副作用を管理することができます。

- この
useEffect
はisCurrent
が変わる
たびに実行されます。isCurrent
が
true のときだけ、viewController.loadRealm()
をマイク
ロタスクで非同期に呼び出します。これにより、
同期処理とぶつからず安全に動かせます。
クリーンアップは不要なので、null
を返して
います。こうして、isCurrent
の状態に応じて
副作用を実行できます。
useState
やuseEffect
以外にも多くのフックがあります。以下は、それぞれのフックとその用途を簡単にまとめた表です。
フック名 | 説明 | 典型的な使用例 |
---|---|---|
useMemoized | 計算結果を依存関係が変わるまでキャッシュします。 | 高コストな計算、オブジェクトの再利用など。 |
useCallback | コールバック関数を依存関係が変わるまでメモ化します。 | 不必要な再ビルドの防止。 |
useRef | 再ビルド間で値を保持しますが、再ビルドのトリガーにはなりません。 | ミューテーブルな参照、コントローラのキャッシュなど。 |
usePrevious | 変数の直前の値を保持・返却します。 | 値の変化検出、トランジション処理、デバッグなど。 |
useMemoisation | useMemoized の旧名(非推奨)。 | useMemoized と同様の用途。 |
useStream | ストリームを購読し、最新の AsyncSnapshot を返します。 | Firebase などのリアルタイムデータ処理。 |
useFuture | Future を購読し、その AsyncSnapshot を返します。 | 一度だけの非同期データ取得。 |
useListenable | Listenable (例: ValueNotifier , AnimationController )を購読。 | コントローラからのリアクティブな更新。 |
useValueNotifier | ValueNotifier を生成して監視します。 | 軽量な状態管理に適しています。 |
useTextEditingController | TextEditingController を生成・破棄の管理も行います。 | テキストフィールドの管理。 |
useAnimationController | AnimationController を生成・破棄します。 | カスタムアニメーションの制御。 |
useTabController | TabController を初期化します。 | タブビューの操作。 |
useFocusNode | FocusNode を生成・管理します。 | キーボードフォーカスの制御。 |
useScrollController | ScrollController を生成・管理します。 | スクロール位置の監視や操作。 |
useTicker | フレーム単位でコールバックを受け取る Ticker を提供します。 | 低レベルのアニメーション制御。 |