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

Next.js中react-dnd useDrop的monitor.isOver({shallow:true})返回值异常

React Dnd shallow模式下isOver判断失效问题

我的Sidebar组件里有可拖拽元素,拖入工作区前需要判断是悬停在工作区本身还是它的子元素上。根据react-dnd文档,monitor.isOver({shallow: true})应该在悬停元素自身时返回true,子元素时返回false,但实际两种情况都返回true。以下是复现代码,求可行解决办法。

请勿提供AI生成的无效建议,我已经试过很多了

export default function TestC() {
const dropRef = useRef(null);

const hRef = useRef(null);
  const [{ isOver, canDrop }, drop] = useDrop(() => ({
    accept: ["element", "component"],
    hover: (item, monitor) => {
      let a = monitor.isOver({ shallow: true });
      console.log(a);
    },
    drop: (item, monitor) => {},
    collect: (monitor) => ({
      isOver: monitor.isOver({ shallow: true }),
      canDrop: monitor.canDrop(),
    }),
  }));
  drop(dropRef);
return (
        <div className="flex justify-around">
          <Sidebar />
          <div className="w-[600px] h-[2000px] border-2 border-dashed border-amber-500">
            <div
              id="a"
              data-wb-id="workspace"
              ref={dropRef}
              role={`Dustbin`}
              className={`w-full h-full`}
              style={{
                backgroundColor: isOver ? "green" : "gray",
                overflow: "auto",
              }}
            >
              <h1 id="b" ref={hRef} className=" border-2 border-orange-400 mb-3">
                Test1
              </h1>
              <p id="c" className="">
                Test2
              </p>
            </div>
          </div>
        </div>
      );
    }

可行解决思路

  • 给子元素添加空drop target拦截
    给工作区的子元素(比如示例中的h1、p)单独注册一个不接受任何拖拽类型的drop target,让子元素优先捕获悬停事件,这样父元素的shallow: true判断就能区分自身和子元素。示例修改:

    // 给h1添加空drop target
    const [, dropH1] = useDrop(() => ({
      accept: [], // 不接受任何拖拽类型
      collect: () => ({}),
    }));
    dropH1(hRef);
    
    // 同理给p也添加
    const pRef = useRef(null);
    const [, dropP] = useDrop(() => ({
      accept: [],
      collect: () => ({}),
    }));
    dropP(pRef);
    
  • 手动计算拖拽位置与元素边界
    不依赖react-dnd的shallow判断,直接通过坐标计算区分。在hover方法里获取拖拽位置和元素的边界矩形,判断鼠标是否在工作区内但不在子元素范围内:

    hover: (item, monitor) => {
      const dropRect = dropRef.current.getBoundingClientRect();
      const h1Rect = hRef.current.getBoundingClientRect();
      const pRect = document.getElementById('c').getBoundingClientRect();
      const { x, y } = monitor.getClientOffset();
    
      // 判断是否仅悬停在工作区自身
      const isOverWorkspaceOnly = 
        x >= dropRect.left && x <= dropRect.right &&
        y >= dropRect.top && y <= dropRect.bottom &&
        !(x >= h1Rect.left && x <= h1Rect.right && y >= h1Rect.top && y <= h1Rect.bottom) &&
        !(x >= pRect.left && x <= pRect.right && y >= pRect.top && y <= pRect.bottom);
      
      console.log(isOverWorkspaceOnly);
    },
    
  • 检查版本与配置
    确认当前react-dnd版本是否存在shallow模式的已知bug,尝试升级到最新稳定版;同时检查工作区元素的ref是否正确绑定,避免嵌套了其他未预期的drop target。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 07:13:22