数据与视图间关系
在过去,我们需要处理当 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 中都去做一些初始化的事情。
而在函数组件中,代码是从业务角度组织在一起的,相关代码能够出现在集中的地方,从而更容易理解和维护。