はじめに
この記事では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/