Reactjs 如何使用React useEffect删除Windows EventListener
在React Hooks文档中,演示了如何在组件的清理阶段移除EventListener 在我的用例中,我试图将VentListener条件删除为功能组件的状态属性 下面是一个从未卸载组件但应移除事件侦听器的示例:Reactjs 如何使用React useEffect删除Windows EventListener,reactjs,react-hooks,removeeventlistener,Reactjs,React Hooks,Removeeventlistener,在React Hooks文档中,演示了如何在组件的清理阶段移除EventListener 在我的用例中,我试图将VentListener条件删除为功能组件的状态属性 下面是一个从未卸载组件但应移除事件侦听器的示例: function App () { const [collapsed, setCollapsed] = React.useState(true); React.useEffect( () => { if (collapsed) {
function App () {
const [collapsed, setCollapsed] = React.useState(true);
React.useEffect(
() => {
if (collapsed) {
window.removeEventListener('keyup', handleKeyUp); // Not the same "handleKeyUp" :(
} else {
window.addEventListener('keyup', handleKeyUp);
}
},
[collapsed]
);
function handleKeyUp(event) {
console.log(event.key);
switch (event.key) {
case 'Escape':
setCollapsed(true);
break;
}
}
return collapsed ? (
<a href="javascript:;" onClick={()=>setCollapsed(false)}>Search</a>
) : (
<span>
<input placeholder="Search" autoFocus />
<a href="javascript:;">This</a>
<a href="javascript:;">That</a>
<input placeholder="Refinement" />
</span>
);
}
ReactDOM.render(<App />, document.body.appendChild(document.createElement('div')));
函数应用程序(){
const[collapsed,setCollapsed]=React.useState(true);
反作用(
() => {
如果(折叠){
window.removeEventListener('keyup',handleKeyUp);//不同的“handleKeyUp”:(
}否则{
window.addEventListener('keyup',handleKeyUp);
}
},
[崩溃]
);
函数handleKeyUp(事件){
console.log(event.key);
开关(事件键){
“逃跑”一案:
设置崩溃(真);
打破
}
}
返回崩溃(
) : (
);
}
ReactDOM.render()
我看到的问题是handleKeyUp
引用在removeEventListener
中每次组件呈现时都在更改。函数handleKeyUp
需要引用setCollapsed
,因此它必须被App
包围。在useffect
中移动handleKeyUp
似乎多次开火并丢失对原始handleKeyUp
的引用
如何在不卸载组件的情况下使用React钩子有条件地window.removeEventListener?您可以将handleKeyUp
函数放在指定给useffect
()的函数中,并且仅在collapsed
为false时添加侦听器并返回清理函数
useEffect(() => {
if (collapsed) {
return;
}
function handleKeyUp(event) {
switch (event.key) {
case "Escape":
setCollapsed(true);
break;
}
}
window.addEventListener("keyup", handleKeyUp);
return () => window.removeEventListener("keyup", handleKeyUp);
}, [collapsed]);
Thole的答案可能有效,但在if
中声明函数是一种不好的做法
当函数被声明时和未声明时,这会使跟踪变得更加困难。此外,由于函数被挂起,这也会导致错误
有一种更简洁的方法来修复它:
通过用钩子包装事件处理程序
useCallback
依赖于setCollapsed
。这确保在组件重新加载时不会重新定义handleKeyUp
(状态更改时总是发生这种情况)
useffect
将有条件地添加/删除事件侦听器,否则只要安装了组件,事件就会一直触发
如果在useEffect中使用了大量事件处理程序,则会有一个自定义挂钩:
下面是用我的解决方案更新的问题海报示例:非常有用!看起来你的useffect
中有额外的收尾花括号。这正是我想要的,非常感谢@publicJorn!为什么要将setCollapsed
作为useCallback
的参数?这不是等价的吗只要做[]
?在上面的例子中,什么定义了事件
?@publicjorn实际上Thole的答案更好,如果可能的话。尽可能在useEffect中定义回调。那么你就不必为useCallback操心了。正如Kent C Dodds所建议的:如果必须为要调用的效果定义函数,请在效果回调内部执行,而不是在外部执行
const [collapsed, setCollapsed] = useState(true)
const handleKeyUp = useCallback((event) => {
if (event.key === "Escape") {
setCollapsed(true)
}
}, [setCollapsed])
useEffect(() => {
if (!collapsed) {
window.addEventListener("keyup", handleKeyUp)
} else {
window.removeEventListener("keyup", handleKeyUp)
}
return () => window.removeEventListener("keyup", handleKeyUp)
}, [collapsed, handleKeyUp])