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

使用D3与React实现拖拽时图形重复问题排查

问题分析与解决方案

为什么会出现两个矩形?

这是**React开发环境的严格模式(Strict Mode)**导致的。开发模式下,Strict Mode会刻意重复调用副作用函数(比如useEffect的回调),用于检测潜在代码问题。你的useEffect每次执行都会调用svg.append('rect'),且没有清理逻辑,两次执行就生成了两个独立的矩形。

拖拽时原位置留图形的本质

并非原位置图形未移动,而是两个矩形初始时重叠在一起,拖拽其中一个后,另一个留在初始位置,视觉上看起来像原图形没动。

用useState出现拖尾的原因

使用useState管理位置时,每次状态更新都会触发组件重新渲染。如果没有正确清理之前用D3创建的旧元素,每次渲染都会新增一个矩形,多个矩形跟随鼠标移动就会形成拖尾效果。

修复步骤

1. 给useEffect添加清理逻辑,避免重复创建元素

修改Comp.jsx中的useEffect,添加清理函数,在组件卸载或useEffect重新执行时移除之前创建的矩形:

useEffect(() => {
    const svg = d3.select(svgRef.current);

    // 创建矩形
    const rect = svg.append('rect')
        .attr('x', 50)
        .attr('y', 50)
        .attr('width', 50)
        .attr('height', 50)
        .attr('fill', 'blue');

    // 修正拖拽逻辑:记录偏移量,让拖拽更自然
    let offsetX, offsetY;
    rect.call(
        d3.drag()
            .on('start', function(event) {
                // 记录鼠标与矩形左上角的偏移距离
                const rectNode = d3.select(this);
                offsetX = event.x - parseFloat(rectNode.attr('x'));
                offsetY = event.y - parseFloat(rectNode.attr('y'));
            })
            .on('drag', function(event) {
                // 用鼠标位置减去偏移量,得到矩形新的左上角坐标
                d3.select(this)
                    .attr('x', event.x - offsetX)
                    .attr('y', event.y - offsetY);
            })
    );

    // 清理函数:移除当前创建的矩形
    return () => {
        rect.remove();
    };
}, []);

2. 优化拖拽位置计算(体验提升)

原拖拽逻辑直接将鼠标位置赋值给矩形的x/y,会导致矩形左上角瞬间跳到鼠标位置,体验生硬。上述代码新增了start事件记录偏移量,拖拽时用鼠标位置减去偏移量,让拖拽行为更符合直觉——点击矩形任意位置,都能从该点开始拖动。

3. 临时关闭Strict Mode(仅作测试)

若要快速验证Strict Mode的影响,可暂时移除index.js中的<React.StrictMode>标签,但不推荐作为最终方案,因为Strict Mode能帮你提前发现潜在代码问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:01:07