React Hook 简介

2/14/2023 React

React Hook 简介

# 前言

今天是情人节,首先祝你们情人节快乐,刚到公司想了想前几天立下的flag,于是便动手开始写React Hook,通过接下来所写的会了解到React Hook工作原理以及推荐使用Hook的理由。共勉

# 什么是Hooks?

Hook是React 16.8版本中新增的一个特性,丰富扩展了原有函数组件的功能,让函数组件拥有了像类组件一样的相似特性。

在之前版本中函数组件不能使用React生命周期函数,Hook本身单词意思就是"钩子",作用就是"钩住某些生命周期函数或某些数据状态,并进行某些关联触发调用"。

不同的Hook(钩子)有不同的作用,可以钩住不同的"点",比如"钩住组件更新完成对应的生命周期函数"、"钩住某个props值的变化"等。

正因为React由多个内置的Hooks,所以本小节的标题才是"什么是Hooks?",是的,用到了Hook的复数单词Hooks。

在React官网中使用的是Hook,我看一些教程使用的是Hooks,都是同一个意思,不要纠结什么时候用单数什么时候用复数。

注意点如下

  1. 尽管函数组件拥有了类组件大多数的相似特征,但有一点除外:函数组件没有类组件中"自定义state"的特性,因此无法在函数组件中使用"this.state.xx"这样的代码。没有不代表功能的缺失,恰恰相反,当了解了Hooks之后,就会发现函数组件内部自定义数据状态功能远超过了类组件。

  2. Hooks只能运行在函数组件的“内部顶层中”,不能运行在if/for等其他函数的代码体内,不允许被if/for等包裹住。

  3. Hooks函数必须为纯函数,所谓纯函数就是函数内部不能修改可能影响执行结果的任意参数,确保每次执行的代码结果都是一样的。

# 为什么要用Hooks?

# 先说一下类组件的缺点

# 缺点1:复杂且不容易理解"this"

例如事件绑定处理函数,都需要bind(this)才可以正确执行。
例如想获取某些自定义属性,都需要使用this.state.xxx或者this.props.xx。
这样造成代码不够精简,并且有些时候热更新不能正常运行,还得重新启动项目。

# 缺点2:组件数据状态逻辑不能重用、组件之间传值过程复杂

"组件数据状态逻辑不能重用" 解释如下:
"组件数据状态"是由:定义数据、默认赋值、获取数据、修改数据、数据逻辑几个环节构成的。由于类组件中的组件数据状态state必须写在该组件构造函数内部,无法将state抽离出组件,因此别的组件如果有类似state逻辑,也必须内部自己实现一次,所以才得出"组件数据状态逻辑不能重用"的结论。

"组件之间传值过程复杂" 解释如下:
React本身为单向数据流,即父组件可以传值给子组件,但子组件不允许直接修改父组件中的数据状态。
子组件为了达到修改父组件中的数据状态,通常采用"高阶组件(HOC)"或"父组件暴露修改函数给子组件(render props)"这2种方式。这2种方式都会让组件变得复杂且降低可复用性。

# 缺点3: 复杂场景下代码难以组织在一起

复杂场景下,比如数据获取(data fetching)和事件订阅(event listeners),相关代码难以组织在一起。

"相关代码难以组织在一起" 解释如下:
第一个"难以组织"的原因:数据获取和事件订阅被分散在不同的生命周期函数中。

例如数据获取:组件第一次被挂载(componentDidMount)、组件每次更新完毕(componentDidUpdate)
例如事件监听:组件第一次被挂载(componentDidMount)、组件即将被卸载(componentWillUnmount)

第二个"难以组织"的原因:内部state数据只能是整体,无法被拆分更细致。

类组件中所有内部数据都被存储在this.state中,例如某个组件定义有2个内部数据name,age,那么永远都是this.state.name、this.state.age。name和age永远都只是this.state中的一个属性,无法做到将name和age拆分成独立对象个体。

所有内部数据都储存在this.state中,当内部数据复杂时,势必增加维护this.state的难度和复杂性。

"复杂场景下代码难以组织在一起"会造成另外一个延伸性问题:加大了代码自动测试难度。

# Hooks是如何解决上述类组件的缺点?

类组件缺点1: 复杂且不容易理解的"this"
Hooks解决方式: 函数组件和普通js函数非常相似,在普通js函数中定义的变量、方法都可以不使用"this.",而直接使用该变量或函数,因此不再需要去关心"this"了

类组件缺点2: 组件数据状态逻辑不能重用
Hooks解决方式: 通过自定义Hook,可以数据状态逻辑从组件中抽离出去,这样同一个Hook可以被多个组件使用,解决组件数据状态逻辑不能重用的问题。

类组件缺点2: 组件之间传值过程复杂 && 类组件缺点3: 复杂场景下代码难以组织在一起
Hooks解决方式: 通过React内置的函数useState()函数,可以将不同数据分别从"this.state"中独立拆分出去。降低数据复杂度和可维护性,同时解决类组件缺点3中"内部state数据只能是整体,无法被拆分更细"的问题。

最为关键的是,hook还能实现一些类组件根本不能实现的功能,比如全局共享数据,代替redux。

# 总结

  1. Hook是React 16.8及以上版本才拥有的特性。
  2. Hook只是React增加的概念和一些API,对原有React体系并没有任何破坏。
  3. Hook有很多优势,比如不再使用"this"、数据状态细致拆分、数据状态逻辑抽离出组件、代码组织更加自由灵活等。
  4. Hook只能用于函数组件,不能用于类组件中。
  5. Hook虽好,但React依然保留对类组件的支持,如果不喜欢Hook,更偏向继续使用类组件,也是ok的。