import React, { useState, useEffect } from "react";
const App = () => {
const [isListening, setIsListening] = useState(false);
const handleScroll = useCallback((index) => {
console.log("The user is scrolling!", index);
}, []);
// 使用useEffect添加和移除事件监听器
useEffect(() => {
if (isListening) {
let index = 1;
console.log("设置事件监听!");
window.addEventListener("scroll", () => handleScroll(index));
return () => {
window.removeEventListener("scroll", handleScroll);
};
}
}, [isListening, handleScroll]);
// 手动控制监听器的添加和移除
const toggleListener = () => {
setIsListening((prevIsListening) => !prevIsListening);
};
// 手动移除监听器
const removeListener = () => {
if (isListening) {
console.log("移除事件监听!");
window.removeEventListener("scroll", handleScroll);
setIsListening(false); // 更新状态以反映监听器已被移除
}
};
return (
<div style={{ height: "1000vh" }}>
<p>滚动页面以查看控制台日志。</p>
<button onClick={toggleListener}>
{isListening ? "停止监听滚动" : "开始监听滚动"}
</button>
<button onClick={removeListener}>手动移除滚动监听</button>
</div>
);
};
export default App;
const els = document.getElementsByTagName("*");
// 例一
for (let i = 0; i < els.length; i++) {
els[i].addEventListener(
"click",
(e) => {
/* 处理点击事件 */
},
false,
);
}
// 例二
function processEvent(e) {
/* 处理同样的点击事件 */
}
for (let i = 0; i < els.length; i++) {
els[i].addEventListener("click", processEvent, false);
}
若希望在 useEffect 中通过 () => handleScroll(index) 设置的监听器能够正确移除,需要确保 removeEventListener 能准确匹配添加的监听器。可以通过为匿名函数显式引用来解决。
import React, { useState, useEffect, useCallback } from "react";
const App = () => {
const [isListening, setIsListening] = useState(false);
const handleScroll = useCallback((index) => {
console.log("The user is scrolling!", index);
}, []);
// 用于保存事件监听器函数的引用
const scrollHandlerRef = React.useRef(null);
useEffect(() => {
if (isListening) {
let index = 1;
console.log("设置事件监听!");
// 将匿名函数赋值给 ref
scrollHandlerRef.current = () => handleScroll(index);
window.addEventListener("scroll", scrollHandlerRef.current);
return () => {
console.log("移除事件监听!");
if (scrollHandlerRef.current) {
window.removeEventListener("scroll", scrollHandlerRef.current);
}
};
}
}, [isListening, handleScroll]);
// 手动控制监听器的添加和移除
const toggleListener = () => {
setIsListening((prevIsListening) => !prevIsListening);
};
const removeListener = () => {
if (isListening && scrollHandlerRef.current) {
console.log("手动移除事件监听!");
window.removeEventListener("scroll", scrollHandlerRef.current);
setIsListening(false); // 更新状态以反映监听器已被移除
}
};
return (
<div style={{ height: "1000vh" }}>
<p>滚动页面以查看控制台日志。</p>
<button onClick={toggleListener}>
{isListening ? "停止监听滚动" : "开始监听滚动"}
</button>
<button onClick={removeListener}>手动移除滚动监听</button>
</div>
);
};
export default App;
import React, { useState, useEffect, useCallback, useRef } from "react";
const App = () => {
const [isListening, setIsListening] = useState(false);
const handleScroll = useCallback((index) => {
console.log(`滚动事件触发,Index: ${index}`);
}, []);
const eventHandlers = useRef([]); // 保存所有事件监听器的引用
useEffect(() => {
if (isListening) {
console.log("设置多个事件监听器!");
// 动态创建监听器
[1, 2].forEach((index) => {
const listener = () => handleScroll(index);
eventHandlers.current[index] = listener; // 保存每个监听器引用
window.addEventListener("scroll", listener);
});
return () => {
console.log("移除所有事件监听器!");
[1, 2].forEach((index) => {
const listener = eventHandlers.current[index];
if (listener) {
window.removeEventListener("scroll", listener);
}
});
eventHandlers.current = []; // 清空监听器引用
};
}
}, [isListening, handleScroll]);
// 控制监听器的添加和移除
const toggleListener = () => {
setIsListening((prevIsListening) => !prevIsListening);
};
const removeAllListeners = () => {
console.log("手动移除所有事件监听器!");
[1, 2].forEach((index) => {
const listener = eventHandlers.current[index];
if (listener) {
window.removeEventListener("scroll", listener);
}
});
eventHandlers.current = []; // 清空监听器引用
setIsListening(false); // 更新状态
};
return (
<div style={{ height: "1000vh" }}>
<p>滚动页面以查看控制台日志。</p>
<button onClick={toggleListener}>
{isListening ? "停止监听滚动" : "开始监听滚动"}
</button>
<button onClick={removeAllListeners}>手动移除所有滚动监听</button>
</div>
);
};
export default App;