在React Hooks文档中,显示了如何在组件的清理阶段删除removeEventListener。 https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect
在我的用例中,我试图删除以功能组件的state属性为条件的EventListener。
在此示例中,从未卸载组件,但应删除事件侦听器:
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')));
(位于https://codepen.io/caqu/pen/xBeBMN的实时示例)
我看到的问题是,handleKeyUp
内的removeEventListener
引用每次在组件呈现时都会改变。函数handleKeyUp
需要引用setCollapsed
,因此必须用App
括起来。将handleKeyUp
移入useEffect
似乎也多次触发,并且失去了对原始handleKeyUp
的引用。
如何使用React Hooks有条件地window.removeEventListener而不卸载组件?
答案 0 :(得分:3)
您可以将handleKeyUp
函数放在给useEffect
的函数中,并且仅添加侦听器,并在collapsed
为假时返回清除函数。
useEffect(() => {
if (!collapsed) {
function handleKeyUp(event) {
switch (event.key) {
case "Escape":
setCollapsed(true);
break;
}
}
window.addEventListener("keyup", handleKeyUp);
return () => window.removeEventListener("keyup", handleKeyUp);
}
}, [collapsed]);
答案 1 :(得分:3)
Tholle的答案可能有用,但是在if
内声明一个函数是不好的做法。声明函数时和不声明函数时,都很难遵循。另外,由于函数被提升,也可能导致错误。
有一种更整洁的方法可以解决它:
通过使用useCallback钩子包装事件处理程序。
const [collapsed, setCollapsed] = useState(true)
const handleKeyUp = useCallback(() => {
switch (event.key) {
case "Escape":
setCollapsed(true)
break
}
}, [setCollapsed])
useEffect(() => {
window.addEventListener("keyup", handleKeyUp)
// See note below
return () => window.removeEventListener("keyup", handleKeyUp)
}
}, [collapsed])
如果您在useEffect中使用了大量事件处理程序,则有一个自定义的钩子:https://usehooks.com/useEventListener/
注意:
由于您正在听keyup
,因此您甚至可能想在collapsed === true
时删除事件侦听器,因为没有任何东西可以折叠。否则,只要安装了组件,事件就会一直触发。
useEffect(() => {
if (!collapsed) {
window.addEventListener("keyup", handleKeyUp)
} else {
window.removeEventListener("keyup", handleKeyUp)
}
return () => window.removeEventListener("keyup", handleKeyUp)
}
}, [collapsed]);