为什么React需要Hook?
2023-05-20 08:50
> 在使用一段时间的hook后,可以说hook对开发体验有很大的改进,解决了以前的痛点。
### 优点
1. 生命周期化作钩子,可以在函数组件内自由使用,逻辑聚合、复用方便;
2. 自定义hook代替高阶组件,更优雅简洁;
3. 不用声明繁杂的类组件,不需要this,可以简化一些代码;
> 但是hook的出现也有一些争议,hook的改进并非完美无缺的,还需要社区去探索一个最佳实践。
### 缺点:
1. 会增加一定心智负担,因为使用useEffect不像以前的生命周期那么直观,需要考虑到依赖的影响,还需要考虑跨渲染次数的数据存储,如果使用不当或者没有做好缓存会经常出现频繁渲染的问题;
2. 因为太灵活,所以团队合作如果大家对hook的熟悉程度不同,写出来的代码上下限会更大;
### class转变为函数
我觉得React在一开始使用类来声明组件,一方面是这个很直观,当你想到状态、方法和渲染函数的集合时,第一反应会是用一个类来承载,另一方面是这也让使用者更好上手,API比较直观容易理解。
类组件的主体是这个类,渲染函数只是其中一部分,但其实并不是每个组件都需要一个复杂的实例,真正的主体应该是那个组件不可或缺的渲染函数,所以其实将一个渲染函数作为一个组件主体才是正确的做法。
于是从类组件到函数组件,只需要将类中的上下文抽离出来,将render函数作为主体,通过钩子的方式为函数组件提供生命周期的访问能力。
### 为什么是这些hook
以前一般我们不会在render函数里放任何副作用代码,因为我们知道render函数会经常重复执行。所以需要引入useEffect来解决这个问题,通过闭包的方式记录下副作用代码,并在DOM渲染完成后执行它。再通过声明依赖的方式去告诉React何时更新并执行这个闭包,很好地代替了mount和update生命周期。
所以一个useEffect实际上是要告诉React,一个函数需要依赖什么状态,并在渲染后执行这个函数。
但光有useEffect和useState还是不够的,函数组件会在每一次渲染重新执行,意味着我们还需要一个能在多次渲染中存储数据的能力,这是用来代替原来class this的部分功能,它就是useRef。至于useMemo和useCallback都是基于useRef的实现,主要起到通过缓存减少渲染次数的作用。
而useReducer则更多的是对状态管理的补充,useState使得状态声明分散,粒度控制比较头疼,加入useReducer,可以将同类型的状态优雅的归类在一起。其他hook都只是一些能力补充,而自定义hook则增强了逻辑的分层和抽象能力,让react hook真正的健壮起来。
有一点需要注意的是,因为hook脱离渲染函数,所以他是怎么确定每个hook的引用呢?答案是首先通过use前缀的约定标记hook,再根据调用顺序来维护引用,每当调用了hook,则把之前存储好的对应顺序位置的引用拿出来即可,这也是为什么hook不允许被条件判断包裹的原因,这会导致hook调用顺序不一致。
增加的这些API确实是给了另一种思维方式,现在整个函数有的只是每一次渲染,所有的hook都是围绕着每一次渲染去执行的。
> 对React的理解尚浅,有错误之处,请务必指出,谢谢!