我正在做一个有很多反模式的项目,我看到的是围绕多个useEffects的IIFE,下面是我的:
condition &&
(() => {
useEffect(() => {
const calOffsetTimeout = setTimeout(() => {
calcOffsetWidth();
}, 150);
return () => {
clearTimeout(calOffsetTimeout);
};
}, [menuWidth.isExpanded, pdfWrapperRef.current]);
useEffect(() => {
calcOffsetWidth();
}, [pdfWrapperRef, desiredScale, zooming]);
useEffect(() => {
calcOffsetWidth();
return () => pdf && pdf.destroy();
}, [pdf]);
useEffect(() => {
window.addEventListener('resize', calcOffsetWidth);
return () => {
window.removeEventListener('resize', calcOffsetWidth);
};
}, []);
})();
它正在工作,但缺点是我不能调试这个生命函数中的任何东西。我想知道把逻辑(尤其是钩子)包裹在生活中是好是坏。我所尝试的是在深度数组内添加条件,但是在项目中有太多的逻辑,一切都停止工作,所以这不是正确的决定。
我尽量详尽地回答这个问题,请耐心等待。
从技术上讲,你可以在任何钩子调用周围使用IIFE。因此,从正确性的角度来看,IIFE不构成问题,但它前面的condition
存在问题。原因如下:所有原始的React钩子useEffect
,useState
,useRef
等都在内部连接到一些React簿记,这完全取决于在一个特定的渲染函数执行期间发生的钩子调用的数量和顺序;猜猜React如何在const [foo] = useState(); const [bar] = useState();
中区分你的foo
状态和bar
状态?简单:两个钩子调用的状态都保存在一个数组中;第一次调用获得第一个槽,第二次调用获得第二个槽,以此类推。因此,当您的条件在运行期间从true更改为false时,并且在您的条件保护表达式之后碰巧有其他useEffect
调用,这些调用将与最初为表达式内的useEffect
创建的插槽相关联。混乱。那么,定制挂钩怎么样呢?好吧,最后,它们是建立在原始的React钩子上的,所以同样的规则也适用。
那么为什么生命是可能的呢?从技术上讲,您的IIFE只是一个匿名自定义钩子。什么是自定义钩子:你可以定义一个内部使用钩子的函数,并像使用任何原始React钩子一样使用你的新函数。按照惯例,钩子被命名为useXXX
,但这只是一个惯例,如果你愿意,你可以将钩子创建为匿名函数。
这样做不好吗?是的。它令人困惑,并没有带来任何有用的东西。如果你想把一些钩子调用分开,那么就把它定义为一个自定义钩子,给它一个有意义的名字,你可以随心所欲地使用输入参数和返回值。