gpt4 book ai didi

javascript - 哪个性能更好 : add and remove event listener on every render VS running an useEffect to update a ref

转载 作者:搜寻专家 更新时间:2023-11-01 04:34:33 24 4
gpt4 key购买 nike

这是我的情况:

我有一个自定义 Hook ,称为 useClick,它获取一个 HTML 元素 和一个 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;

请注意,对于上面的代码,我将在每次调用此 Hook 时添加和删除事件监听器(因为回调,handleClick 在每个渲染)。它必须改变,因为它取决于 myState 变量,该变量在每次渲染时都会改变。

而且我非常希望只在挂载时添加事件监听器并在卸载时删除。而不是在每次调用时添加和删除。


在 SO 上,有人建议我可以使用以下内容:

useClick.js

function useClick(element, callback) {
console.log('Inside useClick...');

const callbackRef = useRef(callback);

useEffect(() => {
callbackRef.current = callback;
}, [callback]);

const callbackWrapper = useCallback(props => callbackRef.current(props), []);

useEffect(() => {
console.log('Inside useClick useEffect...');
const button = element.current;

if (button !== null) {
console.log('Attaching event handler...');
button.addEventListener('click', callbackWrapper);
}
return () => {
if (button !== null) {
console.log('Removing event handler...');
button.removeEventListener('click', callbackWrapper);
}
};
}, [element, callbackWrapper]);
}

问题

它按预期工作。它只在挂载时添加事件监听器,并在卸载时将其删除。

上面的代码使用了一个回调包装器,它使用了一个在渲染中保持相同的 ref(所以我可以将它用作事件处理程序并且只安装一次),以及它的 .current 属性,它通过 useEffect Hook 在每次渲染时使用新的回调进行更新。

问题是在性能方面,哪种方法最好?运行 useEffect() Hook 是否比在每次渲染时添加和删除事件监听器更便宜?

无论如何我可以测试这个吗?

最佳答案

App.js

function App() {
const buttonRef = useRef(null);
const [myState, setMyState] = useState(0);

// handleClick remains unchanged
const handleClick = useCallback(
() => setMyState(prevState => prevState >= 3 ? 3 : prevState + 1),
[]
);

useClick(buttonRef, handleClick);

return (
<div>
<button ref={buttonRef}>Update counter</button>
{"Counter value is: " + myState}
</div>
);
}

更专业的回答:

App.js

function App() {
const buttonRef = useRef(null);
const [myState, handleClick] = useReducer(
prevState => prevState >= 3 ? 3 : prevState + 1,
0
);

useClick(buttonRef, handleClick);

return (
<div>
<button ref={buttonRef}>Update counter</button>
{"Counter value is: " + myState}
</div>
);
}

关于javascript - 哪个性能更好 : add and remove event listener on every render VS running an useEffect to update a ref,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56236043/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com