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 也行。

就这样。感谢阅读!

相关推荐
Revolution619 小时前
reactive 对象重新赋值后,表单为什么没有恢复默认值
前端·vue.js·面试
米饭同学i10 小时前
微信小程序 input maxlength 遇上输入法拼音被截断?这是最完整的解决方案
前端
董员外10 小时前
RAG 系统进化论(二):Naive RAG,检索增强生成的最小闭环
前端·人工智能·后端
脾气有点小暴10 小时前
ECharts 伪 3D 柱状图完整注释 + 实现原理说明
前端·3d·信息可视化·vue·echarts
掘金一周10 小时前
看看大家每月的成本有多少 | 沸点周刊 7.30
前端·人工智能·后端
ji_shuke10 小时前
从零深入:基于 Playwright + Pytest + Allure 的企业级 Web 端到端自动化测试框架实战
前端·自动化测试·docker·jenkins·pytest·allure·playwright
陆枫Larry10 小时前
用 CSS Mask + background-color 给图标「换色」
前端
幼儿园技术家11 小时前
原来不用发版也可以做到版本更新
前端·js or ts
亦暖筑序12 小时前
AgentScope-Java 入门:完善 Vue 前端、发布 GitHub,并规划下一步
java·前端·vue.js
北斗落凡尘12 小时前
Vue面试题
前端