Flutter 需要 Hooks 吗?

原作者并不喜欢 Hooks,认为它们与 Flutter 的设计哲学并不契合,并借此推销他自己的解决方案(state_lifecycle_observer):

截了当地说,我觉得 Flutter 生态系统已经被 Hooks "毒害"了。甚至现在的 AI 工具也会把 Hooks 推荐给初学者,搞得好像它是什么标准架构一样。刚起步的时候我也不懂,只看 pub.dev 上的点赞数(stars);哪个包火,我就用哪个。Riverpod 和 Hooks 我都试过,我觉得都不好------不过这里我只针对 Hooks 展开。 Hooks 不适合 Flutter 的原因在于:它是函数式编程导向的,这与基于面向对象(OOP)的 class 组件(Widgets)天然不匹配。如果你个人偏好这种风格,把它当成一种"语法糖"来用没问题,但不该打着"解决状态复用"或"消除模板代码"的幌子去推广它。这样做只会误导初学者。

这段"生态毒害论"引来了 Remi Rousselet(flutter_hooksproviderriverpod 的作者)的一番回应,语气倒是非常客气:

你这完全是在一个人打一场不存在的仗。其实用 Hooks 的人并不多,而且几乎没人主张把 Hooks 塞进 Flutter 官方框架里。甚至作为 flutter_hooks 的作者,我本人也不认为 Hooks 是 Flutter 的完美方案。 你链接里的那个 Issue,更多是在探讨"Hooks 试图解决的那些痛点",而不是在说"我们需要 Hooks"。 我个人觉得,如果不从语言(Dart)或框架层面做改动,是很难有完美方案的。你的提议确实不错,但语法还是显得太重了,而且也有它自己的坑(特别是当一个"观察对象"依赖于随时间变化的外部数值时,情况会变得非常棘手,尤其是如果这些变化发生在 Widget 生命周期之外的话)

我以前学过 Hooks,但自从用了 GetX 之后,因为它完全消灭了对 StatefulWidget 的需求,自然也就没 Hooks 什么事了,所以我已经把它忘得一干二净。

咱们来复习一下: 当 StatefulWidget 的存在不是为了管理复杂的业务状态,而仅仅是为了初始化和销毁资源(比如 TextEditingControllerFocusNode 之类)时,Hooks 就是一种更简洁的替代方案。

举个例子:如果我们只是想在视图里加一个简简单单的 TextField,通常必须得把整个视图变成 StatefulWidget,然后在 initState 里创建控制器,最后还得在 dispose 里把它销毁掉。

dart 复制代码
class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late TextEditingController _controller;
  
  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold (
        body: Center (
            child: TextField(controller: _controller), 
     ));
  }
}

如果用 Hooks,我们就可以写成这样:

dart 复制代码
class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final _controller = useTextEditingController();
    return Scaffold (
        body: Center (
            child: TextField(controller: _controller), 
     ));
  }
}

useTextEditingController 这个方法能直接帮你创建 TextEditingController 实例,并处理好后续的销毁工作。这非常对我的胃口,完美符合 KISS 原则(简单就是美)。😘

所以,我不吃"Hooks 不适合 Flutter 是因为它是函数式导向,而 Dart 是面向对象"这一套。这说法也许没错,但谁在乎呢?

只要别逼着我去读那些"函数式编程天才"写出来的、长成下面这样的代码就行:

scss 复制代码
filter(...).map(...).filter(...).map(...).reduce(...).slice....

......只要代码别写成那样,我对函数式编程其实没啥意见。

Hooks 的问题在于,它们解决的并不是真正的痛点。

真正的问题出在人们没有使用"正确的架构"(比如 MVVM)以及具备生命周期感知能力的 ViewModel。相反,大家都在用那种所谓的"整洁架构"搭配Riverpod(这玩意儿我也不喜欢 😎)。只有在这种情况下,你才不得不求助于 Hooks。

那什么是"具备生命周期感知能力"的 ViewModel? Flutter 的四大主流状态管理方案中,有三个------Provider、BLoC 和 GetX------都拥有这类 ViewModel。

  • ChangeNotifier 类有一个 dispose 方法,当 ChangeNotifierProvider 从组件树中卸载时,它就会被自动调用。
  • Bloc 有一个 close 方法,同样会在 BlocProvider 卸载时触发。
  • GetxController 则有一个 onClose 方法,会在相关视图卸载时被调用。

**因此,在这些方案中,我们都可以像下面这样写代码:

scala 复制代码
final class MyViewModel extends GetxController {  
final textController = TextEditingController();  
  
void onClose() {  
    textController.dispose();  
    }  
}

根本不需要什么 Hooks。

所以说,Hooks 只有在搭配 Riverpod 或类似的状态管理方案时才算刚需,而这些方案往往并不走 MVVM 架构那套路子。

顺便提一下,利用 Lifecycle 组件,我们可以非常轻松地创建出具备生命周期感知能力的 ViewModel。在这种 ViewModel 内部,你可以随心所欲地使用任何状态管理方案,比如 Signals,甚至你要用 Riverpod 也行。

就这样。感谢阅读!

相关推荐
橙子家6 分钟前
浏览器缓存之【结构化数据库与缓存】: IndexedDB、Cache storage 和 Storage buckets
前端
user205855615181311 分钟前
X6 中边悬浮置顶,规避 `mouseleave` 事件丢失问题
前端
李明卫杭州13 分钟前
CSS aspect-ratio 属性完全指南
前端
Pedantic2 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘2 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆3 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师4 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆4 小时前
VSCode自动格式化三要素
前端
爱勇宝4 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员