🛰️
Signals.dart UI Stateを管理する
👤対象者
- Signalsに興味がある
- 公式はカウンターしかないけどどう使うのか?
- 入力機能で練習して理解する
最近話題のSignalsに興味があって、使ってみた。そもそもこれどんなふうに使えばいいのか?
結論。setState()
メソッドの代わりに、Widgetの状態管理に使います。
使い方
- StatefulWidgetのStateクラスの中に書く
- createSignal(context, 初期値)といった感じで定義する
- flutter_hooksのuseStateに似ている
varで書かないとエラー出る箇所もあるが、基本は、late finalで使う。初期値あるけど、lateいるんだな....
// <T>は、データ型。createSignal(context, T)は、(context, 初期値)です。
late final Signal<T> isDone = createSignal(context, T);
// このほうがわかりやすいか
late final Signal<データ型> isDone = createSignal(context, 初期値);
表示する部分や状態を変更する部分で、値を参照するには、.value
を使います。ここは、flutter_hooks
と似ていますね。
Slider(
value: slider.value,
onChanged: (value) => slider.value = value,
min: 0,
max: 100,
divisions: 100,
),
今回は、カウンター以外にもスライダー、Switch、drop downなどを作りました。
import 'package:flutter/material.dart';
import 'package:signals/signals_flutter.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
ThemeData createTheme(BuildContext context, Brightness brightness) {
return ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: brightness,
),
brightness: brightness,
useMaterial3: true,
);
}
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.system,
home: const CounterExample(),
);
}
}
enum Status {
TODO('未着手'),
INPROGRESS('開始'),
DONE('終了');
final String description;
const Status(this.description);
}
class CounterExample extends StatefulWidget {
const CounterExample({super.key});
State<CounterExample> createState() => _CounterExampleState();
}
class _CounterExampleState extends State<CounterExample> {
// action chip
late var favorite = createSignal(context, false);
// switch light
late final Signal<bool> light = createSignal(context, false);
// checkbox
late final Signal<bool> isDone = createSignal(context, false);
// drop down
late final Signal<Status> status = createSignal(context, Status.TODO);
// slider
late final Signal<double> slider = createSignal(context, 0.0);
// counter
late final Signal<int> counter = createSignal(context, 0);
// counter increment
void _incrementCounter() {
counter.value++;
}
// toggle
void toggle() => isDone.value = !isDone.value;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// switch light
Switch(
value: light.value,
activeColor: Colors.amber,
onChanged: (value) => light.value = value,
),
// action chip
ActionChip(
avatar: Icon(favorite.value
? Icons.favorite : Icons.favorite_border),
label: const Text('Save to favorites'),
onPressed: () {
favorite.value = !favorite.value;
},
),
// slider
Text('Slider value: ${slider.value}'),
Slider(
value: slider.value,
onChanged: (value) => slider.value = value,
min: 0,
max: 100,
divisions: 100,
),
// drop down
DropdownButton<Status>(
value: status.value,
onChanged: (Status? value) {
status.value = value!;
},
items: Status.values
.map((Status status) => DropdownMenuItem<Status>(
value: status,
child: Text(status.description),
))
.toList(),
),
const SizedBox(height: 16),
// checkbox
Checkbox(
value: isDone.value,
onChanged: (value) => toggle(),
),
const SizedBox(height: 16),
const Text(
'You have pushed the button this many times:',
),
// counter
Text(
'$counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
動作はこんな感じです
感想
使ってみた感想ですが、setState()
メソッドと違って、ジャンクが出ているのが少ない気がしました。まだわからないですが🤔
使いこなせればパフォーマンスを上げることができるかもしれない???
aq
さん、よこさんが使っているのをみて興味が出ました。普段は、flutter_hooks
+ hooks_riverpod
ですが、signals
+ flutter_riverpod
を組み合わせてみたいとも思いました。
参考になりそうな記事たち
Discussion
createSignal deprecated
createSignalが非推奨になってしまった😱
代わりにSignalsMixin > createSignalを使用してください。
非推奨のメンバの使用を置き換えてみてください。
修正したコードを参考に今後は試してみてください🙏
まさか破壊的変更が出るとは...
StatefulWidgetのStateクラスにwithでSignalsMixinを多重継承する。