使用 React hooks 转化 class 的一些思考

  • A+

Hooks 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

使用 React hooks 转化 class 的一些思考

  Hooks 其实已经是大势所趋的一个技术了,作为一个可能是 React,甚至是 JS 史上都是一个比较伟大的发明,Hooks 已经被大部分中小型公司所接受并尝试使用,但是对于大中型公司来讲,从 class 组件移植 Hooks 的成本太高,不能像其他公司一样随心所欲地拥抱新技术,所以我们对于 Hooks 的讨论,应该考虑的比较全面,才能更好的了解这个技术,以及是否应该在项目中尝试这一新技术。

  在论坛上我也有和一个小伙伴对此有一个讨论,感谢@无怨,前代 react 项目 class 转 hooks 的必要性。其实大家对 hook 都是认可的,但是对于重写 class 的成本方面还是望而却步的,react 官方也不希望因为这个使得新版本使用者剧减,所以暂时还是会兼容 class 组件的写法。

  所以其实对于是重写部分还是只有新组件使用 hook,大家都还是比较犹豫的,对这种选择来看,我们必须实际考虑成本-产出比,所以我们这篇就具体讨论成本与产出,以及可行的方案吧~

首先咱们来看看成本吧

修改成本

  作为 React 16.8 新增特性,一些第三方的库可能还暂时无法兼容 Hooks,比如 React Redux 从 v7.1.0 才开始支持 Hook API 并暴露了 useDispatch 和 useSelector 等,而 React Router 从 v5.1 开始支持 hooks。所以如果我们的项目中 Redux 和 Router 版本不够的话,可能需要评价是否有必要升级和升级后可能带来的问题。

  再一点,业务逻辑内的代码拆分。在 hooks 中,是不太建议将 state 放置于同一个 state 中的,考虑到性能及区域更新机制,既 state 切分成多个 state 变量,每个变量包含的不同值会在同时发生变化。建议是将 state 根据业务逻辑,拆分成多个 useState。

  这样虽然会增加组件的性能,毕竟每次更新都只是更新一部分组件,但是对于重写 class,我们还需要深入每一个的 class,探究里面 state 的联系、机制等等,是一个较大的阻碍与挑战。

  还有一点,暂时的话,hooks 必须传递 Props 的方式获取根组件 App 中的 state,意思就是如果想使用主 reducer 库中的 state 的话,必须使用 props 传递进来(或通过把 state 也装进 Context 来解决,但是空间成本太大了),只有改变其值才可以 dispatch 来修改

  修改成本可以算成本中最大的一环了,事实上每个 class 组件都可能有非常多的逻辑、状态,各种状态可能都有内在的一些联系。重新去理解这部分代码并重新构建 hooks,其实是一件非常大的挑战,所以本身我暂时对重写 class 到 hooks 是持观望态度,当 React 官方没有一定的苗头出来说不支持 class 写法前,重写的动力确实是不够充足。

学习成本

  hook 本身其实和 class 一样,都是关于本身这个组件的实现细节,重不重写其实对书写正常业务是完全没有影响的(不考虑性能方面的话)。所以 hooks 对于 class 的重写还是会有一定的学习成本在内,毕竟这边要考虑本身与日后入职的小伙伴对这块的熟练度。

时间成本

  按我的预估,对一个完整项目中,class 组件转 hooks,以及部分文件结构整理的时间可能要一个多月(以我的微薄水平),用户看不见明显的功能、UI 修改,不得不说这部分的时间支出是比较大的。

  而如果是原 class 保留不动,新组件使用 hooks 的话,时间成本其实就减少很多了,毕竟新的组件也是从无到有搭建起来,多花的时间可能基本集中在前期对新增 hooks 的结构整理,以及对 redux 仓库的有机结合上,当结构完善,有咱们自己的一套书写模式之后,就可以达到现在书写 class 组件的速度与体验了。

我们能够得到什么?

OK 我们说完了成本,来看看 Hooks 可以带给我们什么?

假设是原 class 组件保留,新建 hooks

  hooks 是一个 React 官方的新特性,Hook 的使用是完全能代替 class 组件的使用,也肯定对其有一个比较大的意义在其中,事实上他们内部原理都是 diff and patch,性能方面差距几乎是可以忽略不计的,但是我的理解是,hooks 更倾向于函数式编程,class 则更倾向于面向对象编程。这是一个大趋势。

  在新的组件中使用 hooks,其实写过之后就能体会到为什么有人说Hooks更骚,class更蠢了。它将所有类似生命周期函数都可以用一个 useEffect 来进行模拟,不会使得自己的逻辑大量分布在 class 的各个角落,大幅度集成业务逻辑代码。

  这是新技术。对没错,我认为新技术本身就是一个我们能够看到的"获得"。在以前我们也会觉得 Jquery 非常好用,以后都会使用这种方式开发,但是后来出现了 webpack,出现了 React、Vue,我们的代码书写形式又变了。新技术的出现本身就是一种信号,只要它接受住了大量业务情况的考验,他的存在就是有某种值得值得去获取的优点,比如后来的组件化、工程化、解耦合等概念。

假设是重写 class 组件

  除了上述优点外,其实就没有过多的其他优点了,只是整个项目的文件结构会更紧凑,毕竟不用兼容 class 写法与 hooks 写法,但是对于性能来说,是没有那种显著提升的。

额外

  性能方面的差距其实是几乎可以忽略不计的,但是函数式编程是越来越火起来的思想,同时 Hooks 从诞生开始就一直在致力于增强其性能,讨论活跃度也足够高,所以可预想的未来内,hooks 性能方面应该会有一个比较大的飞跃。所以这方面也应该是一个可参考的获得。

方案

  说了这么多,其实我们关于 hooks 的选择就只有这三个:

  1. 重写所有 class 组件,转化为 hooks
  2. 原 class 组件不懂,新组件使用 hooks
  3. 原封不动,新组件依旧使用 class 开发

  每个选择都是有各自的考虑的,比如第一个选择考虑的是成本较高,第三个选择是想保持稳定以及开发时间。

  建议假如是新项目或刚刚起步,就全篇使用 hooks 开发(第二种方案),如果已经是稳定上线的项目的迭代,就可以在迭代的组件中使用 hooks,但是如果你的团队需要考虑学习时间成本,本身开发时间较紧张,那么还是建议依旧使用 class 组件进行接下来的开发,因为 class 已经很久了,你的团队一定已经有了一套比较完备的方案与流程来进行接下来的开发,它会让你节省不少的时间。

本文使用 mdnice 排版

90DIR-CMD