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

为何传递空依赖数组时,useEffect中注册的函数仍会执行?

问题分析与解答

首先明确核心逻辑:useEffect的空依赖数组只是让这个副作用函数仅在组件挂载时执行一次(也就是只注册一次事件监听器),并不是阻止事件触发后调用处理函数。只要监听器成功注册到window上,后续鼠标移动时,浏览器就会触发mousemove事件,自然会调用对应的处理函数——这是浏览器的事件机制,和组件是否重新渲染、useEffect是否再次执行完全无关。

再看你代码里的关键错误:
window.addEventListener("onmousemove", handleMouseMove);
这里事件名写错了,addEventListener接受的是不带on前缀的事件名称,正确写法应该是"mousemove"。你当前的代码其实并没有成功注册原生事件,除非手动触发了onmousemove自定义事件,否则handleMouseMove不会被调用。如果实际运行中函数确实被调用了,大概率是你已经把事件名改成了正确的mousemove。

另外补充一个潜在问题:你的handleMouseMove定义在组件内部,每次组件渲染都会重新创建这个函数。虽然空依赖数组让useEffect只执行一次,但注册的是组件第一次渲染时创建的handleMouseMove——如果函数里用到了其他状态或props,就会出现闭包导致的旧值问题。解决这个问题可以用两种方式:

// 方式一:用useCallback包裹函数,确保引用稳定
import { useEffect, useState, useCallback } from "react";

const UseEffect1 = () => {
  const [X, setX] = useState(0);
  const [Y, setY] = useState(0);

  const handleMouseMove = useCallback((e) => {
    setX(e.clientX);
    setY(e.clientY);
  }, []);

  useEffect(() => {
    window.addEventListener("mousemove", handleMouseMove);
    // 务必添加清理函数,避免内存泄漏
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
    };
  }, [handleMouseMove]);

  return (
    <div>
      <p>width {X} - height {Y}</p>
    </div>
  );
};
// 方式二:直接把函数定义在useEffect内部
useEffect(() => {
  const handleMouseMove = (e) => {
    setX(e.clientX);
    setY(e.clientY);
  };
  window.addEventListener("mousemove", handleMouseMove);
  return () => {
    window.removeEventListener("mousemove", handleMouseMove);
  };
}, []);

最后提醒:一定要在useEffect的清理函数中移除事件监听器,否则组件卸载后监听器仍会存在,可能引发内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 10:45:40