前言
Reaact Hooks 是在 2018 年底 v16.7.0-alpha 发布的新特性,当时很多技术群里聊的算是热火朝天,表示 Hooks 重构后的代码是有多简洁,多好用,不过当时并没有第一时间选择重构,而是继续使用 Class Component ,因为 Hooks 刚刚出来,不太稳定,而且相对于生命周期来说更是多了一些心智负担
在 19 年中后我正式开始使用,也写过一些业务,下面就说一下我对 Hooks 的思考
函数组件的新定义
在 React 中有两种组件的创建方式,一种是类组件,一种是函数组件,函数组件相对于类组件来说,大概有以下特点
- 没有状态
- 没有生命周期
- 没有
this
函数组件纯粹由数据生成视图,在项目开发过程中,状态逻辑都在上层容器组件当中采用 class 组件或者说使用类似 Redux 的状态管理利用 HOC 的形式,HOC 其实也就是返回一个包裹子组件的新的类组件 在 Hooks 的影响下,函数组件新增了依赖前置,return 之前有自己的状态,有自己的逻辑副作用需要执行,而后才能返回视图
既然 Hooks 是未来,我们一定要陪跑,那么我们就要好好考虑,在函数组件当中如何更好的运用 Hooks 了,而如何更好的应用我认为仍然是组件分割和抽象、状态划分这些事情上
逻辑复用
目前大家都用了很久的 React Hooks 了,相信useState
是大家最常用的内置 hook,而当使用useState
的时候,会返回一个元组,就是 [ state, setState ]
state 可以是任意值,当然这在类组件中是不提倡的,这就能看出一点,在 Hooks 的体系中,推荐大家使用更细粒度的方法去维护
但是相对于曾经的类组件,经常能在类组件中看到维护一个大的 State,里面存储着不同逻辑的细粒度状态,然后在不同的生命周期里进行部分更新,首先状态定义与变更状态的逻辑是分散的,就是说你无法很快得知某个状态是在哪个setState
完成的
但是在 Hooks 中我们会将状态分散在不同的useState
中,它们的值与变更操作作为一个整体是可感知的
它的设计上来说就是基于useReducer
的简化版,但是当我们简单粗暴的从一个大的状态中拆分出不同细粒度的状态进行管理,它和我们之前的处理也大差不差
这里就要说明 React Hooks 的目标之一逻辑复用,我们可以看到社区已经提供了很多 hook 包或者 hook 片段,比如 React Hooks - 30 seconds of code、react-use、ahooks
React Hooks 本身提供了基础的 hook,比如useMemo
、useCallback
,都可以基于useRef
实现,然后是通过工具函数的 hook 封装,比如防抖、节流等,再可以面向通用业务场景的开发,比如虚拟列表、分页、轮播等,最后才是面向实际业务的 hook 开发
相信我们在业务的开发过程中也知道,有通过业务沉淀下来的 hook,在提高效率上是多么有优势
转变看法
上面也有说到,生命周期也能通过内置 hook 复刻出来,在刚接触 Hooks 的时候,肯定会不由的想起这个概念,我想说的是抛弃曾经的生命周期的概念,换来应该是函数的依赖副作用,我们要考虑一个函数组件的状态的定义,是状态的依赖副作用的处理,才是返回视图更新
在 React Hooks 的内置 hook 中,比如useEffect
,也有自己的依赖,而依赖不更新的时候,useEffect
也不会进行处理,所以在使用 hook 的时候,因为你拿到的值不一定是新的,所有地方都必须小心翼翼,
甚至于说,在抽象 hook 的时候,不允许条件调用,不允许 hook 中调用 hook 等等,以至于发生的一系列抽象的痛苦,或者考虑依赖项是否需要添加,如果使用useCallback
是采用传入参数还是依赖项
当然这些都需要更高的熟练度,比起曾经在不同的生命周期中跳跃处理逻辑,hook 已经帮助我们更好的管理状态和复用逻辑,而且对 Ts 来说支持更友好
总结
在业务中直接使用useState
等 hook 叠加成组件,并不是一个值得提倡的方式,我们更应该思考如何去分割组件,分割 hook,分割 effect,而抽象 hook 是有助于业务研发效率的