关于 signals-and-flutter-hooks
Signals and Flutter Hooks 通过代码示例介绍 Flutter 中从 setState、ValueNotifier 到 signals 和 hooks 的状态管理方式,适合学习响应式状态与组件生命周期的开发者。内容展示了各方案的用法及衔接方式。
主要功能
- 01对比 setState 与 ValueNotifier
- 02通过 signals 实现响应式状态
- 03使用 Watch 更新组件
- 04以 hooks 减少 StatefulWidget 样板代码
- 05在 HookWidget 中使用 signals
适用场景
- 01比较 Flutter 状态管理方式
- 02将状态更新限制在组件子树
- 03在 HookWidget 中共享响应式状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rodydavis/ skills --skill signals-and-flutter-hooks安装后在 Claude Code 中输入/signals-and-flutter-hooks确认已加载。
详细介绍
Signals 和 Flutter Hooks
在使用 Flutter 处理数据时,最先接触到的内容之一就是 setState。
setState
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: Counter()));
}
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
void increment() {
if (mounted) {
setState(() {
count++;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(child: Text('Count: $count')),
floatingActionButton: FloatingActionButton(
onPressed: increment,
child: const Icon(Icons.add),
),
);
}
}
每次调用 setState 时,它只会将 widget 标记为需要重建,但需要你(作为开发者)留意并明确这些更新发生的时机。如果修改数据时忘记调用 setState,widget 树就可能变得过时。
ValueNotifier
我们可以使用 ValueNotifier 来改进这一点,而不是直接存储值。这样,我们就可以在容器中读写值,并使用 ValueListenableBuilder 等辅助 widget,在值发生变化时更新 widget 树的部分区域。
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: Counter()));
}
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
final count = ValueNotifier(0);
void increment() {
count.value++;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(child: ValueListenableBuilder(
valueListenable: count,
builder: (context, value, child) {
return Text('Count: $value');
}
)),
floatingActionButton: FloatingActionButton(
onPressed: increment,
child: const Icon(Icons.add),
),
);
}
}
FlutterSignal
使用 signals 包,我们可以将 ValueNotifier 升级为基于 signal 的实现,它采用基于推送 / 拉取架构的响应式图。
import 'package:flutter/material.dart';
import 'package:signals/signals_flutter.dart';
void main() {
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: Counter()));
}
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
final count = signal(0);
void increment() {
count.value++;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: ValueListenableBuilder(
valueListenable: count,
builder: (context, value, child) {
return Text('Count: $value');
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: increment,
child: const Icon(Icons.add),
),
);
}
}
6.0.0 之后创建的 Signals 也实现了 ValueNotifier,因此无需更改其他代码即可轻松迁移。
我们可以使用 Watch widget 或 .watch(context) 扩展来替代 ValueListenableBuilder。
import 'package:flutter/material.dart';
import 'package:signals/signals_flutter.dart';
void main() {
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: Counter()));
}
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
final count = signal(0);
void increment() {
count.value++;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Text('Count: ${count.watch(context)}'),
),
floatingActionButton: FloatingActionButton(
onPressed: increment,
child: const Icon(Icons.add),
),
);
}
}
flutter_hooks
使用 Flutter Hooks,我们可以改用 HookWidget,减少 StatefulWidget 的样板代码。借助 useState,我们可以直接在 build 方法中定义状态,并轻松地在 widget 之间共享。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void main() {
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: Counter()));
}
class Counter extends HookWidget {
const Counter({super.key});
@override
Widget build(BuildContext context) {
final count = useState(0);
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(child: Text('Count: ${count.value}')),
floatingActionButton: FloatingActionButton(
onPressed: () => count.value++,
child: const Icon(Icons.add),
),
);
}
}
useState 会返回一个 ValueNotifier,值发生变化时会自动重建 widget。
signals_hooks
借助新的包 signals_hooks,我们现在可以在 HookWidget 中定义 Signals,并获得响应式图的优势,同时还能在 widget 之间共享生命周期。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:signals_hooks/signals_hooks.dart';
void main() {
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: Counter()));
}
class Counter extends HookWidget {
const Counter({super.key});
@override
Widget build(BuildContext context) {
final count = useSignal(0);
final countStr = useComputed(() => count.value.toString());
useSignalEffect(() {
print('count: $count');
});
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(child: Text('Count: $countStr')),
floatingActionButton: FloatingActionButton(
onPressed: () => count.value++,
child: const Icon(Icons.add),
),
);
}
}