引子:hooks如今使用的越来越频繁,但函数式编程和class组件的理解却不尽相同,导致转换过程中仍然照搬生命周期那一套,导致实现效果差强人意,虽然形似,却实际背道而驰!
如今,站在其他前辈的肩膀上,有幸能够理解useEffect的概念,着实让我感到庆幸,所以我想分享下关于useEffect要注意的点!
其一:基本概念之副作用
顾名思义,在完成某件事时附带执行的事,在useEffect的基本概念中,他表明了,在dom构建完成才执行,因为主要事是dom构建,所以其被称之为副作用,这里着重要注意的就是渲染时机了 =====> dom构建完成
其二:cleanup函数
其意为,副作用的清除,副作用会产生影响,因此我们需要消除它,从个人角度看,这个cleanup和生命周期的willUnmount真的太像了,可是实际上却不然,为什么?
我们都知道willUnmount表示的是组件卸载的生命周期,那cleanup呢?他只是副作用的清除操作罢了!副作用可以在组件挂载,重绘之后任意执行,那cleanup就永远只是清除上一个
副作用的函数罢了,那为什么cleanup又可以模拟willUnmount呢?那么就不得不说其三了!
其三:依赖项
副作用不可以每次渲染组件都执行,因此在每次渲染之后都需要判断其是否值得执行,由此出现依赖项,这有点类似与pureComponent(同样也是useMemo的基本)的理念,即
shallowEqual -> 浅比较,与第二点的关联处在于,当每次副作用执行时,若依赖项为空,代表着副作用只会在函数执行的第一次执行,在effect更新队列中,他在整个函数周期中基本上不会被干掉,只有当函数真正的卸载时,才会执行!
从上述而言,不知道有人发现没?
cleanup的真正用处是用于清除每一个上一次的effect的,他更应该用来针对每一次副作用做操作,而不完全是针对函数卸载来操作,
然而实际上在使用过程中,大多数人都喜欢添加空依赖项,或者就是单纯加一个cleanup函数,就以为能在函数卸载时执行了
由此,不正确的做法导致了与使用目的背离的理念,那么使用起来也就奇奇怪怪了!
那么,该如何正确使用?
我且说说依赖项,cleanup上述已讲:
依赖项的目的是什么?监听函数组件中的数据流变化,无论是props还是useState中的state变量,都应当被纳入到依赖项中,条件是:只要你的副作用会使用到这些变量,那么你就需要加入进去,别问为什么别人可以通过eslint-disable-line来取消依赖或者是使用ref来不触发重渲染,而我这里不这样做。
为什么?因为没必要,不符合涉及理念,当你需要时刻知道变量最新值的时候,为什么不让组件知道呢?就好比你需要食物来填饱肚子,但是服务员只端给你十分之一的食物,而你很明显没吃饱,但是服务员并不会继续端给你吃,为什么?因为你根本就没和人家说我还要再吃,那你自己饿肚子怪谁?
那么,请记住了,当你的副作用需要跟随数据流变化时,请记得一定要添加上去,并且切莫将数据流的变化写在副作用中,因为这时就是主作用了,而你加入到副作用中,能不进入死循环嘛?但从副作用这一层就能看出,他只是伴随主作用(组件重渲染)而进行的罢了,而你将副作用当做主作用来使用,那能怪谁呢?