Hooks 二三事 (2) | 可视化对比引入 Hooks 前后代码量

上一篇文章中,提及 「Hooks 就是让你更容易做你已经在做的事情」。那么”容易“二字体现在哪里呢?今天要分享的这篇文章就从可视化角度,量化用 Hooks 重构组件前后的代码量,并探讨在思维模式上的转变。
原文链接:https://wattenberger.com/blog/react-hooks

一年前,React 团队提出了 Hooks,改变了社区内很多开发者的开发习惯。网上有大量的文章在介绍 Hooks 的基本功能 ,但本文将探讨 ”类组件“ 与 ”函数组件 + Hooks“ 两种开发模式下思维方式的转变。

生命周期

  • 在类组件中,我们会在特定的生命周期函数中进行更新操作。

  • 在函数组件中,我们使用 useEffect 钩子在必要的生命周期中执行代码。

图1

通过这个示例,你可能会想:”好吧,useEffect 就是提供了一种在生命周期中执行代码的新方式。“ 然而,这个结论是不够全面的。接下来一起看看这个更为完善的例子,比如有一个计算开销很大的 getDataWithRange() 函数,该函数根据指定的 dataRange 返回筛选后的数据。这该怎么办呢?为了减少重复的计算开销,我们会希望把它存储到 state 对象中,当且仅当 dataRange 发生改变时才更新它。

  • 使用生命周期中的事件,我们需要在某一个点上处理所有的变化。我们的思考过程是这样的:“当组件开始加载和参数发生变化时(特指 dataRange ),更新 data 状态”。
  • 在函数组件中,我们需要思考的是哪些数据需要保持同步,思考的过程会是:“ data 需要与 dataRange 保持同步” 。
图2

这样的思考过程是不是简化了许多。但是,上述的例子中,我们依旧是在类组件的思想框架中思考问题。我们将 data 存储到 state 中,以此来避免每次组件更新中重新计算 data 值。现在,我们完全可以不用 state!Hooks 提供了 useMemo 方法来解决这个问题,当且仅当依赖数组内的任一元素发生变化时,才重新计算 data 值。

图3

更新上下文

是否还觉得不够直观?那就再看看这个更加复杂的例子吧,可以让你更深刻的体会到两种思考模式的认知负担差距。

假设我们在组件中有很多需要实时计算的值,它们依赖于不同的 props。比如,我们需要计算:

  • data:当 dataRange 改变时更新;
  • dimesions:当 margins 改变时重新计算;
  • scales:当 data 改变时需要同步更新。

在函数组件中,我们能够快速快速逻辑关系,比如“让 dimesionsmargins 保持同步”。

即使在这样简单的示例中类组件也显得特别笨重。这是因为我们有很多声明类的代码,用来解释如何使代码中的变量与 propsstate 保持同步,而在函数组件中, 我们只需要关注哪些数据需要保持同步。

注意,我们在代码中使用了很多次 useMemo() 钩子,以此拉近依赖项副作用的“距离”

宽松地定义状态

再加点逻辑,如果 scales 需要根据图表中的 dimension 改变,又该怎么做呢?

  • 在类组件中,我们需要对比 prevState 和当前的 state
  • 在函数组件中,hooks 并不关心依赖数组中的 marginsdimesion 是来自于 state 还是 props,还是两者都不是,对它而言,值就是一个值。
image-20200721142731529.png

总结

代码简洁

代码量少不一定容易阅读,让保持组件代码的简洁一定是一种胜利。接下来让我们快速比较一下上述示例的代码行数吧:

Hooks 二三事 (2) | 可视化对比引入 Hooks 前后代码量_第1张图片
图4

从左到右为上述的 5 个示例代码量,左边的柱状长度表示「类组件」代码行数,右边的柱状长度表示同样功能下的「函数组件+ Hooks」代码行数

函数组件的平均代码行数是类组件的 46.1%。另外,再比较一下核心版本中主要的代码差异:

Hooks 二三事 (2) | 可视化对比引入 Hooks 前后代码量_第2张图片
图5

堆叠图中每层的颜色与示例动图中的连接带颜色保持一致

可以看到我们是如何按功能逻辑将相关代码统一到一起的,而不是分散在多个生命周期事件中。

逻辑复用

Hooks 赋予了我们在组件之间共享功能逻辑的能力,而不需要去操作组件的生命周期事件。当然,使用类组件的编写模式时,你也可以利用高阶组件来实现这一需求,但是高阶组件所带来的麻烦比它创造的价值更多,经常把 render 函数搞得一团糟。

我(Amelia Wattenberger )从参与的众多项目中提取并维护了一个简单的 Hooks 仓库,降低了开发成本。从我的角度来讲,复杂功能逻辑的复用带来的便利包括:

  • 不必重复一些通用模式,比如:保证图表的比例与容器一致。在实现上,会是逻辑复杂、行数不少的代码块,如果需要不断在每个图表中实现,将是令人奔溃的。
  • KISS (Keep it simple and stupid)——让我在思考的时候能够专注于某一个点,确保我不会漏掉某个重要的环节,比如解绑事件等。

译者言

个人的一些看法:

  • 文中使用的案例代码都相对简单,但量化的过程是个不错的方法,我们有没有办法在实际项目中通过打点的方式做类似的比较呢;
  • 文中提到的 useMemo 的使用,也许可以作为可视化保持复杂数据同步的一个规范;
  • Hooks 在功能逻辑复用上面的优势,可以通过建立团队内部的 hooks 仓库发挥出来。

你可能感兴趣的:(Hooks 二三事 (2) | 可视化对比引入 Hooks 前后代码量)