広告 Flutter Dart Unity アプリ開発

flutter_hooks覚書

概要

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で宣言するような使い方になります。

サンプルソースは後日、追記します。

-Flutter Dart Unity アプリ開発