はじめに
この記事ではFlutterの状態管理ライブラリであるsignalsを簡単に利用しています。
- カウンター+テーマモード変更(signalsのexample)
- todoアプリ
 の2つを実装してみます.
記事の内容でアドバイス等ありましたら、コメントや編集リクエストで優しく教えてくださると幸いです
実装
インストール
flutter pub add signals
のコマンドで導入できます。
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  signals: ^1.4.1
追加されていますね。
公式ドキュメントの例の実装
exampleのコードをそのまま実装します.
例ではデフォルトで作成されるカウンターアプリと同じものに、テーマモードの切り替えの機能が実装されています。
テーマモードの切り替え部分
final brightness = signal(Brightness.light);
この部分ではsignalの初期化を行なっています。
signal()の引数が初期値となります。
final themeMode = computed(() {
  if (brightness() == Brightness.dark) {
    return ThemeMode.dark;
  } else {
    return ThemeMode.light;
  }
});
computed()は既存のシグナルを複数組み合わせて、新しいシグナルを生成することができます。
今回はbrightnessを基にしてthemeModeを生成るようです。
ここで作成したthemeModeはMyApp内の
themeMode: themeMode.watch(context),
で使われており、.watch()でsignalの変更をUIに反映しています。
Watch((_) {
            final isDark = brightness() == Brightness.dark;
            return IconButton(
              onPressed: () {
                brightness.value = isDark ? Brightness.light : Brightness.dark;
              },
              icon: Icon(isDark ? Icons.light_mode : Icons.dark_mode),
            );
          }),
ここではbrightnessシグナルの値によってアイコンボタンの切り替えを行います。また、アイコンボタンが押下されるとbrightnessを更新しています。
counter部分
カウンターもテーマと同じように作成されています.
  final counter = signal(0);
  void _incrementCounter() {
    counter.value++;
  }
counterというシグナルとそれを1インクリメントするメソッドを作成してあります。
値の表示は以下のようにWatch()で行われます。
Watch((context) {
              return Text(
                '$counter',
                style: Theme.of(context).textTheme.headlineMedium!,
              );
            }),
todoアプリ
画像のようなシンプルなtodoアプリを実装してみました。
使っているのはexampleにもあったものばかりなので詳細は省きます。
コード
import 'package:flutter/material.dart';
import 'package:signals/signals_flutter.dart';
// todoリストのシグナルを作成する
final todoItems = signal<List<String>>([]);
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'totoアプリ',
      home: ToDoPage(),
    );
  }
}
class ToDoPage extends StatelessWidget {
  const ToDoPage({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'タスクリスト',
        ),
        backgroundColor: Colors.purple.shade100,
      ),
      // Watch()関数でtodoItemsに基づくUIを管理する
      body: Watch((_) => ListView.builder(
            itemCount: todoItems.value.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(todoItems.value[index]),
                trailing: IconButton(
                  icon: const Icon(
                    Icons.delete,
                    color: Colors.red,
                  ),
                  onPressed: () {
                    var updatedList = List<String>.from(todoItems.value);
                    updatedList.removeAt(index);
                    todoItems.value = updatedList;
                  },
                ),
              );
            },
          )),
      floatingActionButton: FloatingActionButton(
        onPressed: () => _showAddTaskDialog(context),
        backgroundColor: Colors.purple.shade100,
        child: const Icon(
          Icons.add,
        ),
      ),
    );
  }
  void _showAddTaskDialog(BuildContext context) {
    showDialog<String>(
      context: context,
      builder: (BuildContext context) {
        String newTask = '';
        return AlertDialog(
          title: const Text('タスクを追加する'),
          content: TextField(
            onChanged: (value) => newTask = value,
            decoration: const InputDecoration(
              hintText: 'タスクを入力する',
            ),
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                if (newTask.isNotEmpty) {
                  var updatedList = List<String>.from(todoItems.value);
                  updatedList.add(newTask);
                  todoItems.value = updatedList;
                }
                Navigator.pop(context);
              },
              child: const Text('追加'),
            ),
          ],
        );
      },
    );
  }
}
最後に
今回は簡単なアプリしか作成しませんでしたが、非常に使いやすい状態管理のパッケージな気がしました。
もう少し規模大きめなアプリでも使ってみたいですね👀
参考
https://pub.dev/packages/signals
https://pub.dev/documentation/signals/latest/

