For this exact case you’re right because undefined
is passed as the dependencies of useEffect
.
This means useEffect
runs on every render and thus the event handlers will unnecessarily get detached and reattached on each render.
function listener() {
console.log('click');
}
function Example() {
const [count, setCount] = window.React.useState(0);
window.React.useEffect(() => {
console.log(`adding listener ${count}`);
window.addEventListener("click", listener);
return () => {
console.log(`removing listener ${count}`);
window.removeEventListener("click", listener);
};
}); // <-- because we're not passing anything here, we have an effect on each render
window.React.useEffect(() => {
setTimeout(() => {
setCount(count + 1);
}, 1000)
});
return count;
}
window.ReactDOM.render(window.React.createElement(Example), document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
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.
function listener() {
console.log('click');
}
function Example() {
const [count, setCount] = window.React.useState(0);
window.React.useEffect(() => {
console.log(`adding listener ${count}`);
window.addEventListener("click", listener);
return () => {
console.log(`removing listener ${count}`);
window.removeEventListener("click", listener);
};
}, []); // <-- we can control for this effect to run only once during the lifetime of this component
window.React.useEffect(() => {
setTimeout(() => {
setCount(count + 1);
}, 1000)
});
return count;
}
window.ReactDOM.render(window.React.createElement(Example), document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>