I have this code:
const App: React.FC = () => {
const [isOpen, setIsOpen] = React.useState(true);
const [maxHeight, setMaxHeight] = React.useState();
const wrapper = React.useRef<HTMLDivElement>(null);
const content = React.useRef<HTMLDivElement>(null);
const setElementMaxHeight = () => {
if (content && content.current) {
setMaxHeight(isOpen ? content.current.offsetHeight : 0);
}
};
useEffect(() => {
setElementMaxHeight();
window.addEventListener("resize", setElementMaxHeight);
return () => {
window.removeEventListener("resize", setElementMaxHeight);
};
});
const toggle = () => {
setIsOpen(!isOpen);
};
return (
<div>
<button onClick={toggle}>
<span className="nominal-result__expander fa" />
</button>
<div
className="nominal-results__list-wrapper"
ref={wrapper}
style={!!maxHeight ? { maxHeight: `${maxHeight}px` } : undefined }
>
<div className="nominal-results__list" ref={content} />
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This will add and remove an event handler on each render.
Is this necessarily bad and does this actually gain anything from being a hook?
This came up in a code review and I am saying it is bad because it adds and removes the event listener on every render.
For this exact case you're right because
undefined
is passed as the dependencies ofuseEffect
.This means
useEffect
runs on every render and thus the event handlers will unnecessarily get detached and reattached on each render.But if you explicitly declare no dependencies by passing in an empty array
[]
,useEffect
will only run once, thus making this pattern perfectly legitimate for event handler attachment.