假设我们有一个带有复选框的简单的基于函数的组件。
我很好奇为什么随后添加和删除事件侦听器会成功:
function Component() {
const handler = () => 123
useEffect(() => {
window.addEventListener("beforeunload", handler)
window.removeEventListener("beforeunload", handler)
}, [isChecked])
}
Run Code Online (Sandbox Code Playgroud)
但是当引入一个条件时,例如:
function Component() {
const handler = () => 123
useEffect(() => {
isChecked
? window.addEventListener("beforeunload", handler)
: window.removeEventListener("beforeunload", handler)
}, [isChecked])
}
Run Code Online (Sandbox Code Playgroud)
侦听器已添加,但不再删除。
这是为什么?是因为我们的处理程序是在重新渲染时重新创建的吗?当处理程序移出组件时,一切都井然有序。
这是一个演示,供那些想要测试它的人使用:
https://codesandbox.io/s/y8jono6yx?module=%2Fsrc%2FCheckbox.jsx
指示:
npm i在下载的文件夹中运行npm start事件侦听器列表可以通过调用来检索getEventListeners(window)- 至少在 Chrome 中是这样。
问题是handler每个组件渲染上都有新功能。window.removeEventListener("beforeunload", handler)是无操作的,因为该handler函数从未注册为beforeunload侦听器。
handler应该移到组件函数的范围之外:
const handler = () => 123;
export default function Checkbox() {
const [isChecked, setIsChecked] = useState(false);
useEffect(
() => {
isChecked
? window.addEventListener("beforeunload", handler)
: window.removeEventListener("beforeunload", handler);
},
[isChecked]
);
...
};
Run Code Online (Sandbox Code Playgroud)
由于handler无法以这种方式访问组件函数作用域,因此可以做的事情非常有限。更传统的方法是使useEffect回调仅执行一次(与 相对应)并从(与 相对应)componentDidMount返回一个函数。由于在函数的作用域中使用了same ,所以问题就消失了,但另一个问题是不能与 一起使用,因为它使用的是在初始渲染期间定义的函数,并且将始终在其作用域内。可以用于此目的(演示):useEffectcomponentWillUnmounthandleruseEffecthandleruseStatehandleruseEffectisCheckedfalseuseRef
export default function Checkbox() {
const isCheckedRef = useRef(false);
const handler = () => {
if (isCheckedRef.current)
...
};
useEffect(
() => {
window.addEventListener("beforeunload", handler);
return () => {
window.removeEventListener("beforeunload", handler);
}
},
[]
);
return (
<input
type="checkbox"
checked={isCheckedRef.current}
onChange={e => isCheckedRef.current = e.target.checked}
/>
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5801 次 |
| 最近记录: |