Ich habe diesen 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);
Dadurch wird bei jedem Rendern ein Ereignishandler hinzugefügt und entfernt.
Ist das unbedingt schlecht und bringt es tatsächlich etwas, ein Haken zu sein?
Dies ist bei einer Codeüberprüfung aufgetaucht und ich sage, dass es schlecht ist, weil es den Ereignis-Listener bei jedem Rendern hinzufügt und entfernt.
Dafür genau Falls du recht hast, weil undefined
wird als Abhängigkeiten von übergeben useEffect
.
Das heisst useEffect
wird bei jedem Rendern ausgeführt und daher werden die Ereignishandler bei jedem Rendern unnötigerweise getrennt und wieder angehängt.
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>
Wenn Sie jedoch explizit keine Abhängigkeiten deklarieren, indem Sie ein leeres Array übergeben []
, useEffect
wird nur einmal ausgeführt, sodass dieses Muster für die Anbringung von Event-Handlern vollkommen legitim ist.
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>