You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何useEffect清理函数移除未添加的事件监听器不报错?

为什么移除未添加的事件监听器不会报错?

先看你的代码场景:

import React from "react";
import "./style.css";
import { useState, useEffect } from 'react';

export default function App() {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  const [canMove, setCanMove] = useState(false);

  useEffect(() => {
    function handleMove(e) {
      setPosition({ x: e.clientX, y: e.clientY });
    }
    if (canMove)
      window.addEventListener('pointermove', handleMove);

    return () => window.removeEventListener('pointermove', handleMove);
  }, [canMove]);

  return (
    <>
      <label>
        <input type="checkbox"
          checked={canMove}
          onChange={(e) => {
            setCanMove(e.target.checked)
            }
          } 
        />
        The dot is allowed to move
      </label>
      <hr />
      <div style={{
        position: 'absolute',
        backgroundColor: 'pink',
        borderRadius: '50%',
        opacity: 0.6,
        transform: `translate(${position.x}px, ${position.y}px)`,
        pointerEvents: 'none',
        left: -20,
        top: -20,
        width: 40,
        height: 40,
      }} />
    </>
  );
}

你遇到的情况是:首次渲染时canMove为false,useEffect没给window添加pointermove监听器;当勾选复选框把canMove改成true,useEffect重新执行前会先运行清理函数——调用window.removeEventListener('pointermove', handleMove),但之前根本没注册过这个监听器,却没有报错。

原因很直接:浏览器原生的removeEventListener API本身是容错设计。不管你要移除的监听器有没有注册过,或者是否和已注册的监听器匹配,浏览器都会直接忽略这个无效操作,不会抛出任何错误。

补充说明:每次useEffect执行时,都会创建一个全新的handleMove函数实例。但哪怕是同一个函数实例,只要没通过addEventListener注册过,调用removeEventListener也不会有问题——浏览器只会默默跳过这个无效的移除请求。

内容的提问来源于stack exchange,提问作者Indra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:25:12