R

React Hooks 发布回顾:两年后 最初的反应 蜜月期 第一年 两年后 那么发生了什么? 我们接下来该去哪里?

2025-06-07

React Hooks 发布两年回顾

最初的反应

蜜月期

第一年

两年后

那么发生了什么?

我们接下来要去哪里?

这篇文章代表了我对事件的看法,也可能是一段虚构的叙述。我之所以反思,是因为我认为 Hooks 的发布是过去五年来前端开发最重要的转折点。它的影响至今仍在,并将持续数年。至于结果如何,留给你们自己去评判吧。

2018年10月26日,React 宣布了一项将改变整个前端生态系统的功能。如果你还没看过这篇演讲,可以在这里找到

描绘一下这幅图景。React 几乎征服了前端世界。在人们讨论“JavaScript 疲劳”并描绘出每月框架的碎片化格局的两年之后,React终于占据了主导地位。当然,还有VueAngular。但大多数其他库都已销声匿迹。React 已经达到了一个里程碑,超越了日渐式微的 jQuery。

React 16 巩固并精简了诸多未完善之处。这一愿景可以视为 React 成功证明其可以像 Web 开发一样轻松地用于原生开发。而且,似乎在不久的将来还会推出许多颇具前景的功能。一切看起来都在向好的方向发展。

最初的反应

React 内部

在今年早些时候引入了时间片和并发模式的概念之后,我不确定大家是否期待着其他新东西。当然,我们刚刚经历了从智能/愚蠢组件、渲染 props 到recompose等的循环,感觉一切都稳定下来了。也许它并不完美,但 React 似乎能解决任何问题。

这个公告让我们大多数人措手不及。解决方案非常优雅直接。通过将类的生命周期拆分成多个事件订阅方法或“钩子”,我们可以使用函数组件,并充分利用状态的功能。这不仅让我们能够按功能对状态/动作/效果进行分组,从而简化了代码,还彻底解决了自 以来一直存在的混合和可扩展性问题React.createClass

我的意思是,Dan 还没说完,它的价值就已经显现出来了。那些位于组件定义之上的 HOC 堆栈将变成简单的、近乎声明式的 JS 块。这非常简洁,而且真的改变了游戏规则。不知怎么地,他们一下子就解决了所有问题。

React 外部

我最近听了一个播客,Svelte 的创始人 Rich Harris 回忆了第一次看到 Hooks 时的感受。他当时觉得大家可能不会接受 Hooks,但后来的反应让他很惊讶。

诚然,我对这份声明的反响同样感到惊讶。我敢发誓,Dan Abramov 刚刚告诉 React 开发者,Web 开发的未来是 KnockoutJS/MobX。它们的 API 和组合模式非常相似。我很喜欢 KnockoutJS,并且一直秉持 React 的理念,这最终导致了它的市场份额下降。

这听起来很疯狂,但大家都很接受。我明白为什么。他们似乎解决了我在使用 React 时遇到的所有问题。我最终能放弃响应式,并像以前一样爱上 React 吗?

我认为这个方向既合理,又让其他社区感到困惑。有人认为 React 更倾向于函数式编程。另一些人则真诚地认为:“我们不是终于在 JavaScript 中引入了类吗?他们到底在干什么?” 不少像 Vue 这样的库都遵循了这一点,试图弄清楚 ES 类在它们的框架中应该是什么样子,而 React 已经再次改变了范式。

蜜月期

React 内部

在最初的三个月里,我们经历了一场文艺复兴。人们创建了use____集合库,所有可以成为 Hook 的东西都很快变成了 Hook。对于我们所有简单的示例来说,这都非常棒。表单验证、存储界面、动画助手、时间/日期助手等等,不胜枚举。

后来有人尝试做一个计数器。你知道,那种随处可见的简单计数器,数字永远不更新,永远保持为 1。

import React, { useState, useEffect } from "react";
import { render } from "react/dom";

const App = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => setCount(count + 1), 1000);
    return () => clearInterval(timer));
  }, [])

  return <div>{count}</div>;
};

render(() => <App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

那一刻,我们第一次意识到事情并非我们一直以来所想的那样。好吧,我们知道了 Hook 规则,那么为什么不把过时的闭包也加进去呢?而且,使用函数形式也能setCount解决这个问题,所以我们就到处都这么做吧。

当然,另一个想法是,也许我们不需要 Redux 了?Context API 加上 useReducer 就足够了。说实话,React 已经内置了所有工具,我们还需要这些外部状态库吗?就连 Redux 6 本身也已经按照惯例转而使用 React 新的 Context API 了。

React 外部

我敢肯定,在一天之内,每个响应式 UI 库的作者都会顿悟:“React 永远不会成为最好的 Hooks 库”。事情似乎有些不对劲。Hook 规则表明,心智模型与现实之间存在差距。

Hooks API 主要是响应式开发者非常熟悉的模式,所以他们几乎可以立即发现这个缺陷。不难想象,Svelte 的 Rich Harris 曾因语法冲突而反思所有这些库究竟缺少了什么。他最终得出结论,我们需要的只是在 JavaScript 语言中添加响应式功能,这样就能摆脱所有这些繁琐的负担。

Vue 的 Evan You 当时可能在想:“嘿,我们已经有一个库可以实现这个功能了。解决方案很简单,而且不用那些 Hook Rules 也能搞定。” 他很快宣布 Vue 将在 Vue 3 中公开他们的响应式系统。

就我个人而言,我仍然不敢相信 React 的发布,因为Solid的 API 在 Hooks 发布之前就已经几乎与 Hooks 完全相同了。但他们解决了我使用元组的 getter/setter 问题。这是我最不需要的,而且我意识到 Solid 可能是一个值得尝试的库,因为它不仅性能出色,而且是与 React 最接近的 API 接口,没有那些怪异之处,而且人们似乎很喜欢它。我在 2018 年 11 月写了第一篇文章,从那以后就一直没有停止写作。

第一年

React 内部

Hooks 几乎取代了一切。说实话,这种炒作是有道理的。Hooks 无处不在。人们重构了他们的项目。新的 React 感觉很棒。

事实证明,Redux并没有消亡。如果使用 React 的状态进行变更管理,Context API 会存在性能问题,因此在 Redux 7 中,它迅速转向使用自己的订阅系统。

如果说 MobX 等反应式库开始衰落的话,那么 MobX 的创建者 Michel Westrate 发布了一款很棒的库(Immer),让使用 Redux 变得更加容易。

其他库也开始出现,以更好地处理数据获取层,并且使用 Hooks 使它们看起来更容易引入我们的项目。

所以,是的,Hooks 确实存在一些小问题。我们仍然偶尔会忘记依赖项,但我们的 Linter 能很快找到它们。有时,当我们想要那个空的依赖项数组时,我们不得不强制它停止运行。

公平地说,我们之前从未如此深入地理解 React 的工作原理。当我们回顾我们的类组件时,我们意识到它充满了我们从未意识到的风险。然而,我们的代码应该比以往更高效、更精良。

React 外部

2019 年 3 月,Svelte 3 正式发布,意义非凡。Rich Harris 告诉我们,我们或多或少已经做了太多事情,而且时间太长了,我们真正需要做的就是摆脱它。他成功地将响应式特性融入了 Svelte 语言,并以无人能否认的方式展现了出来。小巧、高性能、易用,所有方面都得到了充分的体现。

Vue 宣布放弃其类提案,并用函数 API 取而代之。该 API 后来演变为 Composition API,成为 Vue 3 的基础,它为框架提供了“类似 Hook”的响应式原语,避免了 Hook 规则或闭包问题。社区陷入分裂,但 Evan 仍然出色地引领着这艘大船。

许多其他库也像 React 一样添加了 Hook。Preact做出了巨大的改变, Preact X 引入了 Hook 和许多新的 React 16 API。这确实导致库体积略有增加,但到了 2019 年 9 月,我们有了具有相同现代 API 的 React 替代方案。此外,还有一些很棒的项目,例如Augmentor,可以为任何渲染器/Web 组件添加 Hook。

至于 Solid,我已经有了想要的原语。相反,我花了一年时间实现了所有我能找到的 React 特性,以便让它在浏览器中达到同等的功能水平。最后一个特性是实验性的 Suspense 和 Concurrent 支持,于 2019 年秋季正式发布。

两年后

在 Hooks 诞生的第一年,反应式库迎接了创建最佳的基于原始语法的框架的挑战。React 无意中打开了一扇大门,让反应式库长期以来一直被视为自己的强项。React 本身仍然蓬勃发展,但这对于库来说是一个获得认可的重要机会。

第二年,React 取得了更惊人的进展。自主研发的全局状态库成功地利用了 React 自身的原语,例如 Recoil、Hookstate 等……它们能够以前所未有的方式优化利用 React 自身的原语。然而,一些令人不安的事情仍然潜伏在表面之下。

其他库,例如 Svelte,也已经发展壮大,Vue 3 也已发布。这些库在第二年致力于提升开发者体验,这一点已经显现出来。

但最明显的一点是,当问到“如何在 React 中最好地实现 X?”这个问题时,答案变得混乱得多。过去,人们讨论的是哪种抽象最流行。现在,人们讨论的焦点是如何讨论 React 内部工作原理。甚至在某个自作聪明的人插嘴说“但在并发模式下,情况可能会完全改变”之前,答案的可信度就已经大大降低了。

Jared Palmer 的《React 正在变成黑匣子》或许最能体现这种感觉

那么发生了什么?

长期以来,人们很容易将 Suspense 的等待和围绕并发模式的早期实验归因于事态发展的明显催化剂。但我认为这一切都要归功于 Hooks 的发布。

Hooks 既是 React 历史上最好的东西,也是最糟糕的东西。我感同身受,因为我也经历过。你花了数年时间思考哪些方面可以改进,最终意识到,如果以某种方式整合所有元素,就能弥补所有不足。这甚至与你亲身经历的愿景相符。然而,你之外的人从未见过你所看到的东西,而现在他们也不确定自己是否喜欢。

React 永远不会成为最好的 Hooks 库。你不需要在某件事上做到最好才能做好。但如果你的 Hooks 库主观上是最差的呢?

React Hooks 真是天才之作。对于需要理解具体工作原理的普通开发者来说,或许这太天才了。React 保留了 VDOM 的所有优势,view = fn(state)强大的渲染器,以及细粒度声明式数据方法的灵活性,而开发者只需关注更新即可。

响应式系统其实并不简单,但它们的细粒度原语中却体现了这种“写入即忘”的特性。Svelte 或 Vue 正是因此而拥有这种感知上的简洁性,尽管从机制上来看,它们在某些方面比你想象的更相似。React 的方法可以说比 Vue 更纯粹,因为它与 VDOM 的本质紧密相连,而不是试图在其上搭建一个响应式系统,但目前还没有 Vue 开发者考虑过这个问题。

此外,React 对许多人来说最大的吸引力在于其对共享状态管理的开放态度。React 引入了自己的原生功能,自然而然地取代了其他库。它并没有强制它们被淘汰,但 API 表面的重叠以及使用 React 内部机制的知识更有益于此。对于像 MobX 这样的侵入式响应式库来说尤其如此。

我们接下来要去哪里?

React 团队这几年可不是无所事事。我相信一切很快就会水落石出。React 依然会是最常用的前端库。但有些东西已经永远改变了。

一些杰出的 React 开发者已经跳槽。看看他们的新旅程是否也能带来同样的发展,将会非常有趣。React 诞生于简化渲染模型的愿望,此前几年,你猜对了,它一直沿用事件驱动/响应式库。我们应该谨慎地抛弃所有我们学到的东西。这些东西往往像钟摆一样摇摆不定,一开始就会过度修正。

其他人则转向尽可能减少 React 组件中的状态管理。这包括使用其他形式的状态管理来从外部驱动 React,以避免 React 团队开发的任何功能。XState一个状态机库,在其他一些库中越来越受欢迎。

不管是好是坏,我们都必须承认,现在的前端库比以往任何时候都更加相似,这给竞争带来了完全不同的局面。这使得在性能和大小等其他因素相同的情况下,竞争会更加激烈。

我们现在看到了像JSX-Lite这样的东西,它可以将通用的 JSX API 编译到你选择的框架中。我很好奇,未来的 Metaframeworks 是否会为了保持其选择的开放性而构建支持多个框架的功能?考虑到对新独特功能的渴望,这很难成为先例。但或许,厌恶风险的人会接受最低标准。

也许这最终还是会发生的。但那一天,React 打开了一扇永远无法关闭的大门。

文章来源:https://dev.to/ryansolid/the-react-hooks-announcement-in-retrospect-2-years-later-18lm
PREV
TypeScript 的问题
NEXT
固体状态 - 2021 年 9 月