之前写过一篇文章:juejin.cn/post/756852...
最近有人在评论区指责我不懂 hooks、不懂 signals、不懂前端潮流。那篇文章中,我对 hooks 还保留了一些余地,认为某些场景下可能确实有其必要性。但直到我深入研究了 flutter_hooks 这个库的起源,我的想法发生了改变。
事情的起因是,该库作者在 github.com/flutter/flu... 中提出状态复用困难的问题,希望借鉴 React 的 hooks 模式来解决。但 Flutter 官方维护者并不认同 hooks 与状态复用之间存在必然联系,因此不打算提供官方支持。
尽管如此,作者在这几年里始终坚持自己的观点,创建了 flutter_hooks 库,将 React 的那套 API 完整地移植到了 Flutter 中。
我个人也反对将 hooks 引入 Flutter。如果问题是状态复用困难,难道 hooks 就是唯一的解决方案吗?显然不是。
我们完全可以借鉴 Android 的 LifecycleObserver 模式,将逻辑抽离出来实现最大化复用,达到与 hooks 相同甚至更好的效果。本质上,hooks 也是对生命周期的一种封装,只是它在封装生命周期之外还附加了许多额外功能。但这些额外功能与状态复用的核心问题关系不大,我认为这更像是为了使用 hooks 而强行引入 hooks。
具体实现代码 :github.com/lwj1994/sta...
使用文档
Flutter State Observer
使用 Observer 模式解决状态复用问题的 Flutter 包。
特性
- LifecycleObserver: 用于创建可复用状态观察者的基类。
- LifecycleObserverMixin : 用于在
State中管理观察者生命周期的 mixin。 - 常用观察者 :
AnimControllerObserver: 可复用的AnimationController逻辑。ScrollControllerObserver: 管理ScrollController。TabControllerObserver: 管理TabController。TextEditingControllerObserver: 管理TextEditingController。
用法
自定义观察者
你可以通过继承 LifecycleObserver 轻松创建自己的观察者。
示例:一个 UserDataObserver,它能够:
- 在
onInit中初始化数据获取。 - 在
onUpdate中当userId变化时重新获取数据。 - 在
onBuild中记录调试信息。
dart
import 'package:flutter/material.dart';
import 'package:state_lifecycle_observer/state_lifecycle_observer.dart';
class Data {
final String id;
final String info;
Data(this.id, this.info);
}
class UserDataObserver extends LifecycleObserver<ValueNotifier<Data?>> {
// 获取 Widget 最新参数的机制
final String Function() getUserId;
// 用于追踪变化的内部状态
late String _currentUserId;
UserDataObserver(
super.state, {
required this.getUserId,
});
@override
void onInit() {
target = ValueNotifier(null);
_currentUserId = getUserId();
_fetchData(_currentUserId);
}
@override
void onUpdate() {
// 检查依赖 (userId) 是否发生变化
final newUserId = getUserId();
if (newUserId != _currentUserId) {
debugPrint('UserId changed from $_currentUserId to $newUserId');
_currentUserId = newUserId;
_fetchData(_currentUserId);
}
}
@override
void onBuild(BuildContext context) {
debugPrint('Building with user: $_currentUserId');
}
@override
void onDispose() {
target.dispose();
}
void _fetchData(String id) async {
// 模拟网络请求
await Future.delayed(const Duration(milliseconds: 500));
if (_currentUserId == id) { // 避免竞态条件
target.value = Data(id, 'Info for $id');
}
}
}
与 flutter_hooks 的比较
| 特性 | state_lifecycle_observer | flutter_hooks |
|---|---|---|
| 范式 | OOP (类) | 函数式 (Hooks) |
| 基类 | 标准 StatefulWidget |
HookWidget |
| 生命周期 | 显式 (onInit, onDispose) |
隐式 (useEffect) |
| 学习曲线 | 低 (标准 Flutter) | 中 (Hooks 规则) |
| 黑魔法 | 低 (Mixin + List) | 高 (Element 逻辑) |
| 条件逻辑 | 随处支持 | 不允许在 build 中使用 |