在React Hooks文档中,展示了如何在组件清理阶段删除EventListener。 https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect
在我的用例中,我试图将条目的removeEventListener删除为功能组件的状态属性。
下面是一个示例,其中组件永远不会卸载但应删除事件侦听器:
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?
你可以将handleKeyUp
函数放在给useEffect
给出的函数内部,只有当collapsed
为false时才添加监听器并返回一个清理函数。
useEffect(() => {
if (!collapsed) {
function handleKeyUp(event) {
switch (event.key) {
case "Escape":
setCollapsed(true);
break;
}
}
window.addEventListener("keyup", handleKeyUp);
return () => window.removeEventListener("keyup", handleKeyUp);
}
}, [collapsed]);