2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ぬいぐるみ欲しいカレンダーAdvent Calendar 2023

Day 4

Signalsの状態管理を使ってみた

Last updated at Posted at 2023-12-03

はじめに

この記事ではFlutterの状態管理ライブラリであるsignalsを簡単に利用しています。

  • カウンター+テーマモード変更(signalsのexample)
  • todoアプリ
    の2つを実装してみます.

記事の内容でアドバイス等ありましたら、コメントや編集リクエストで優しく教えてくださると幸いです

実装

インストール

flutter pub add signals

のコマンドで導入できます。

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  signals: ^1.4.1

追加されていますね。

公式ドキュメントの例の実装

exampleのコードをそのまま実装します.

image.png

例ではデフォルトで作成されるカウンターアプリと同じものに、テーマモードの切り替えの機能が実装されています。

テーマモードの切り替え部分

main.dart
final brightness = signal(Brightness.light);

この部分ではsignalの初期化を行なっています。
signal()の引数が初期値となります。

main.dart
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に反映しています。

main.dart
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部分

カウンターもテーマと同じように作成されています.

main.dart
  final counter = signal(0);

  void _incrementCounter() {
    counter.value++;
  }

counterというシグナルとそれを1インクリメントするメソッドを作成してあります。
値の表示は以下のようにWatch()で行われます。

main.dart
Watch((context) {
              return Text(
                '$counter',
                style: Theme.of(context).textTheme.headlineMedium!,
              );
            }),

todoアプリ

画像のようなシンプルなtodoアプリを実装してみました。

Simulator Screenshot - iPhone 15 Pro - 2023-12-03 at 05.28.13.png

使っているのはexampleにもあったものばかりなので詳細は省きます。

コード
main.dart
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/

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?