移除flutter_hooks中useEffect的使用:非流变量依赖转换难题
替代flutter_hooks中带非流依赖的useEffect方案
1. StatefulWidget结合didUpdateWidget+实例变量追踪依赖变化
这是最贴合Flutter原生的替代方案,核心是在State类中保存上一次的依赖值,通过对比新旧值触发逻辑,同时在生命周期方法中处理初始化和资源清理。
原hooks代码示例:
useEffect(() { // 执行业务逻辑:基于nonStream和propsFromRiverpod做操作 final subscription = someStream.listen((data) {}); return () => subscription.cancel(); // 清理资源 }, [nonStream, propsFromRiverpod]);
转换后的StatefulWidget实现:
class MyWidget extends StatefulWidget { final String nonStream; final PropsType propsFromRiverpod; const MyWidget({super.key, required this.nonStream, required this.propsFromRiverpod}); @override State<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { // 保存上一轮依赖值,用于对比变化 late String _prevNonStream; late PropsType _prevPropsFromRiverpod; StreamSubscription? _subscription; @override void initState() { super.initState(); // 初始化时记录初始依赖 _prevNonStream = widget.nonStream; _prevPropsFromRiverpod = widget.propsFromRiverpod; // 执行首次逻辑 _executeLogic(); } @override void didUpdateWidget(covariant MyWidget oldWidget) { super.didUpdateWidget(oldWidget); // 只要任意一个依赖变化,就重新执行逻辑 if (widget.nonStream != _prevNonStream || widget.propsFromRiverpod != _prevPropsFromRiverpod) { _cleanup(); // 更新依赖记录 _prevNonStream = widget.nonStream; _prevPropsFromRiverpod = widget.propsFromRiverpod; _executeLogic(); } } @override void dispose() { _cleanup(); super.dispose(); } void _executeLogic() { // 原useEffect中的业务逻辑 _subscription = someStream.listen((data) {}); } void _cleanup() { // 原useEffect返回的清理逻辑 _subscription?.cancel(); _subscription = null; } @override Widget build(BuildContext context) { // UI构建代码 return Container(); } }
注意:如果依赖是复杂对象,必须确保其正确实现了==运算符(比如用freezed生成或手动重写),否则依赖变化检测会失效。
2. 结合Riverpod的ref.listen处理状态依赖
如果依赖项包含Riverpod状态,可以把状态监听交给ref.listen,非流变量仍用didUpdateWidget追踪,两者触发时统一执行逻辑。
示例代码:
class MyWidget extends ConsumerStatefulWidget { final String nonStream; const MyWidget({super.key, required this.nonStream}); @override ConsumerState<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends ConsumerState<MyWidget> { late String _prevNonStream; StreamSubscription? _subscription; @override void initState() { super.initState(); _prevNonStream = widget.nonStream; // 首次执行逻辑 _executeLogic(ref.watch(myProvider)); // 监听Riverpod状态变化 ref.listen(myProvider, (_, newProps) { _cleanup(); _executeLogic(newProps); }); } @override void didUpdateWidget(covariant MyWidget oldWidget) { super.didUpdateWidget(oldWidget); if (widget.nonStream != _prevNonStream) { _prevNonStream = widget.nonStream; _cleanup(); // 基于当前Riverpod状态执行逻辑 _executeLogic(ref.watch(myProvider)); } } @override void dispose() { _cleanup(); super.dispose(); } void _executeLogic(PropsType props) { // 结合nonStream和props执行业务逻辑 _subscription = someStream.listen((data) {}); } void _cleanup() { _subscription?.cancel(); _subscription = null; } @override Widget build(BuildContext context) { return Container(); } }
3. 使用ValueNotifier封装非流变量,统一监听逻辑
如果依赖项较多,可以把非流变量包装成ValueNotifier,再和Riverpod状态的监听源合并,统一处理所有依赖变化。
示例代码:
class MyWidget extends ConsumerStatefulWidget { final String nonStream; const MyWidget({super.key, required this.nonStream}); @override ConsumerState<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends ConsumerState<MyWidget> { late final ValueNotifier<String> _nonStreamNotifier; StreamSubscription? _subscription; late final Listenable _mergedListenable; @override void initState() { super.initState(); _nonStreamNotifier = ValueNotifier(widget.nonStream); // 合并多个监听源:非流变量的ValueNotifier + Riverpod状态的监听 _mergedListenable = Listenable.merge([ _nonStreamNotifier, ref.listenable(myProvider), ]); // 添加统一的变化回调 _mergedListenable.addListener(_onDependenciesChanged); // 首次执行逻辑 _executeLogic(); } @override void didUpdateWidget(covariant MyWidget oldWidget) { super.didUpdateWidget(oldWidget); if (widget.nonStream != _nonStreamNotifier.value) { _nonStreamNotifier.value = widget.nonStream; } } @override void dispose() { _mergedListenable.removeListener(_onDependenciesChanged); _nonStreamNotifier.dispose(); _cleanup(); super.dispose(); } void _onDependenciesChanged() { _cleanup(); _executeLogic(); } void _executeLogic() { final props = ref.watch(myProvider); final nonStream = _nonStreamNotifier.value; // 业务逻辑执行 _subscription = someStream.listen((data) {}); } void _cleanup() { _subscription?.cancel(); _subscription = null; } @override Widget build(BuildContext context) { return Container(); } }
内容的提问来源于stack exchange,提问作者Lucky
相关产品推荐
相关产品推荐

