Вот моя ситуация:
У меня есть пользовательский хук, называемый useClick
, который получает HTML element
и callback
в качестве входных данных, присоединяет click
прослушиватель событий к этому element
, и устанавливает callback
в качестве обработчика события .
App.js
function App() {
const buttonRef = useRef(null);
const [myState, setMyState] = useState(0);
function handleClick() {
if (myState === 3) {
console.log("I will only count until 3...");
return;
}
setMyState(prevState => prevState + 1);
}
useClick(buttonRef, handleClick);
return (
<div>
<button ref={buttonRef}>Update counter</button>
{"Counter value is: " + myState}
</div>
);
}
useClick.js
import { useEffect } from "react";
function useClick(element, callback) {
console.log("Inside useClick...");
useEffect(() => {
console.log("Inside useClick useEffect...");
const button = element.current;
if (button !== null) {
console.log("Attaching event handler...");
button.addEventListener("click", callback);
}
return () => {
if (button !== null) {
console.log("Removing event handler...");
button.removeEventListener("click", callback);
}
};
}, [element, callback]);
}
export default useClick;
Обратите внимание, что с кодом выше, Я буду добавлять и удалять прослушиватель событий при каждом вызове этой ловушки.
И я бы очень хотел, чтобы добавлял только при монтировании и удалял при размонтировании. Вместо добавления и удаления при каждом вызове.
Даже если я использую это:
useEffect(()=>{
// Same code as above
},[element,callback]); // ONLY RUN THIS WHEN 'element' OR 'callback' CHANGES
Проблема в том, что даже если element
( ref ) останется неизменным во всех рендерах, callback
(, которая является функцией handleClick из приложения ), изменить на каждом рендере. Поэтому я все равно добавляю и удаляю обработчики на каждом рендере.
Я также не могу преобразовать handleCLick
в useCallback
, потому что это зависит от переменной состояния myState
, которая изменяется при каждом рендеринге, и мой useCallback
все равно будет воссоздан при каждом рендере (когда myState
изменения), и проблема будет продолжаться.
const handleClick = useCallback(()=> {
if (myState === 3) {
console.log("I will only count until 3...");
return;
}
setMyState(prevState => prevState + 1);
},[myState]); // THIS WILL CHANGE ON EVERY RENDER!
ВОПРОС:
Пример для CodeSandbox
Должен ли я беспокоиться об удалении и подключении даже слушателей на каждом рендере? Или это действительно совсем не дорого и не имеет шансов навредить моей производительности ? Есть ли способ избежать этого?