起因
当我在 Hooks
内使用 addEventListener
监听 scroll
事件时,然后使用 removeEventListener
移除监听发现移除失效。
const scroll = () => {
useEffect(() => {
document.addEventListener("scroll", scrollCallback);
}, []);
const scrollCallback = (e) => {
console.log(e)
}
const clearScroll = () => {
document.removeEventListener("scroll", scrollCallback);
}
return <button onClick={clearScroll}>Clean</button>;
}
这是一个在初始化完成后会在 document
添加一个 scroll
事件监听,点击按钮之后会清除监听事件。
但是事实上并不会按照预想的方式执行,在点击按钮之后并不会清除 scroll
事件;
每一次渲染都有它自己的事件处理函数
Hooks
每次渲染的时候事件都是自己的内部重新定义的,所以 removeEventListener
在移除的时候判定到的 scrollCallback
不是同一个回调函数, 这里有更详细的介绍。
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
把内联回调函数及依赖项数组作为参数传入 useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。这里有更详细的介绍。
改造
const scroll = () => {
const eventListener = useCallback((e) => scrollCallback(e), []);
useEffect(() => {
document.addEventListener("scroll", eventListener);
}, []);
const scrollCallback = (e) => {
console.log(e)
}
const clearScroll = () => {
document.removeEventListener("scroll", eventListener);
}
return <button onClick={clearScroll}>Clean</button>;
}