My Little World

hook 产生原因

数据与视图间关系

在过去,我们需要处理当 Model 变化时,DOM 节点应该如何变化的细节问题。
而现在,我们只需要通过 JSX,根据 Model 的数据用声明的方式去描述 UI 的最终展现就可以了,
因为 React 会帮助你处理所有 DOM 变化的细节。而且,当 Model 中的状态发生变化时,UI 会自动变化,即所谓的数据绑定。

所以呢,我们可以把 UI 的展现看成一个函数的执行过程。
其中,Model 是输入参数,函数的执行结果是 DOM 树,也就是 View。
而 React 要保证的,就是每当 Model 发生变化时,函数会重新执行,并且生成新的 DOM 树,然后 React 再把新的 DOM 树以最优的方式更新到浏览器。

class组件不合适的原因

一方面,React 组件之间是不会互相继承的。比如说,你不会创建一个 Button 组件,然后再创建一个 DropdownButton 来继承 Button。
所以说,React 中其实是没有利用到 Class 的继承特性的。

另一方面,因为所有 UI 都是由状态驱动的,因此很少会在外部去调用一个类实例(即组件)的方法。
要知道,组件的所有方法都是在内部调用,或者作为生命周期方法被自动调用的。

所以你看,这两个 Class 最重要的特性其实都没有用到。

函数组件的缺陷/hooks产生的背景

只是当时有一个局限是,函数组件无法存在内部状态,必须是纯函数,而且也无法提供完整的生命周期机制。这就极大限制了函数组件的大规模使用。
那么我们自然就知道了,Class 作为 React 组件的载体,也许并不是最适合,
反而函数是更适合去描述 State => View 这样的一个映射,但是函数组件又没有 State ,也没有生命周期方法。
以此来看,我们应该如何去改进呢?

hooks的产生

简单想一下,函数和对象不同,并没有一个实例的对象能够在多次执行之间保存状态,那势必需要一个函数之外的空间来保存这个状态,而且要能够检测其变化,从而能够触发函数组件的重新渲染。
再进一步想,那我们是不是就是需要这样一个机制,能够把一个外部的数据绑定到函数的执行。当数据变化时,函数能够自动重新执行。
这样的话,任何会影响 UI 展现的外部数据,都可以通过这个机制绑定到 React 的函数组件。
在 React 中,这个机制就是 Hooks。
所以我们现在也能够理解这个机制为什么叫 Hooks 了。
顾名思义,Hook 就是“钩子”的意思。

在 React 中,Hooks 就是把某个目标结果钩到某个可能会变化的数据源或者事件源上,那么当被钩到的数据或事件发生变化时,产生这个目标结果的代码会重新执行,产生更新后的结果

对于函数组件,这个结果是最终的 DOM 树;对于 useCallback、useMemo 这样与缓存相关的组件,则是在依赖项发生变化时去更新缓存。

hooks 好处一 逻辑复用

Hooks 中被钩的对象,不仅可以是某个独立的数据源,也可以是另一个 Hook 执行的结果,这就带来了 Hooks 的最大好处:逻辑的复用

class高阶组件缺陷

更为糟糕的是,高阶组件几乎是 Class 组件中实现代码逻辑复用的唯一方式,其缺点其实比较显然:
代码难理解,不直观,很多人甚至宁愿重复代码,也不愿用高阶组件;
会增加很多额外的组件节点。每一个高阶组件都会多一层节点,这就会给调试带来很大的负担。

使用hooks封装好处

通过 Hooks 的方式进行封装,从而将依赖变成一个可绑定的数据源。
这样当窗口大小发生变化时,使用这个 Hook 的组件就都会重新渲染。而且代码也更加简洁和直观,不会产生额外的组件节点。

hooks好处二 有助于关注分离

在 Class 组件中,代码是从技术角度组织在一起的,例如在 componentDidMount 中都去做一些初始化的事情。
而在函数组件中,代码是从业务角度组织在一起的,相关代码能够出现在集中的地方,从而更容易理解和维护。