function Panel() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const onResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", onResize);
// cleanup goes here
}, []);
return <div>{width}</div>;
}
return () => window.removeEventListener("resize", onResize);The effect must return a cleanup function, and it must pass the same function that was added. React runs the cleanup when the panel unmounts. Without it, every opening adds one more listener, and each listener keeps the old component's state alive.
"() => onResize()" is the tempting wrong answer. It creates a new function, so removeEventListener finds no match and removes nothing. "React removes listeners" is wrong too. React cleans up only the handlers you pass in JSX, like onClick, not listeners you add to window yourself. The same rule applies to setInterval, subscriptions and observers.