I'm working on a project with lots of anti-patterns, and what I saw is IIFE around multiple useEffects, here is what I have:
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);
};
}, []);
})();
It's working, but the downside is that I can't debug a single thing inside this iife function. I would like to know how bad or good it is to wrap logic (especially hooks) into iife. What i've tried is to add condition inside the deps arrays, but there is too much logic in the project and everything stops working, so it is not the right decision.
I try to answer this a thoroughly as I can, bear with me.
Technically you can use an IIFE around any hook calls. So from a correctness point of view the IIFE does not pose an issue, but the condition
infront of it does. Here is the reason for this: All the original React hooks useEffect
, useState
, useRef
, etc. are wired internally to some React book-keeping that absolutely depends on the number and order of hook calls that happen during one specific render function execution; guess how React can differentiate between your foo
state and your bar
state in const [foo] = useState(); const [bar] = useState();
? Easy: the state for both hook calls are kept in an array; the first call gets the first slot, the second call gets the second slot, and so forth. So when your condition changes during runtime from true to false and you happen to have other useEffect
calls after your conditionally guarded expression those will be associate with slots that were originally created for useEffect
inside the expression. Mayhem.
So what with custom hooks? Well, in the end they are build upon original React hooks, so the same rules apply.
So why is an IIFE possible? Technically your IIFE is just an anonymous custom hook. What is a custom hook: You can define a function that internally uses hooks, and use your new function as you would use any original React hook. By convention hooks are named useXXX
but that is only an convention and you could create a hook as an anonymous function if you wanted.
Is it bad practise to do so? Yes. It is confusing and does not bring anything useful to the table. If you want to separate some hook calls, then just make it a custom hook, give it a meaningful name, you can make use of input arguments and return values as you like.