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

Next.js 13中react-d3-tree缩放与拖拽功能失效求助

解决Next.js 13中react-d3-tree缩放拖拽功能不稳定/失效的问题

针对你遇到的react-d3-tree缩放、拖拽功能不稳定甚至完全失效的问题,可从以下几个方向排查修复:

1. 避免不必要的组件重渲染

react-d3-tree内部依赖D3绑定事件,组件频繁重渲染会导致事件监听被重置。可通过缓存props避免这类问题:

缓存Tree组件的配置参数

在roadmap.tsx中用useMemo缓存Tree的props,防止每次渲染生成新对象:

"use client"

import { useMemo } from 'react';
import Tree from 'react-d3-tree';
import { Node } from '../utils/d3/interfaces/Node';

interface RoadmapProps {
  data: Node[];
}

export default function Roadmap({ data }: RoadmapProps) {
  const treeProps = useMemo(() => ({
    data,
    zoomable: true,
    scaleExtent: { max: 1, min: 0.1 },
    draggable: true,
    translate: { x: 600, y: 100 },
    orientation: "vertical",
    pathFunc: "step" as const,
  }), [data]);

  return (
    <section>
      <div id="treeWrapper" style={{ width: '80vw', height: '100vh', overflow: 'hidden', position: 'relative' }}>
        <Tree {...treeProps} />
      </div>
    </section>
  )
}

缓存父组件传递的数据

在page.tsx中,若nodes是动态生成或API获取的,用useMemo缓存数据,避免每次渲染传递新数组:

// page.tsx
import { useMemo } from 'react';
import Roadmap from './roadmap';

export default async function Home() {
  const nodes = useMemo(() => {
    // 你的数据生成/获取逻辑
    return [
      {
        "name": "Checkpoint 2",
        "attribute": { "id": "18f7db92-b5cf-46b5-9641-08ceac16ca6e" },
        "children": [/* 子节点数据 */]
      }
    ];
  }, []);

  return (
    <main className="max-w-7xl mx-auto lg:px-16 px-6 bg-slate-400">
      <Roadmap data={nodes} />
    </main>
  )
}

2. 修复容器样式与事件捕获问题

D3的拖拽、缩放依赖正确的DOM事件捕获区域,调整容器样式确保事件能被触发:

  • 给treeWrapper添加position: relative,确保SVG元素相对于容器正确定位
  • 禁用浏览器默认触摸行为,避免移动端交互冲突
#treeWrapper {
  width: 80vw;
  height: 100vh;
  overflow: hidden;
  position: relative;
  touch-action: none;
}

同时检查页面其他元素是否遮挡了Tree容器,确保SVG元素处于最上层。

3. 处理Hydration不匹配问题

Next.js 13 App Router中,服务端组件与客户端组件的hydration可能导致D3事件绑定失效,可延迟渲染Tree组件:

"use client"

import { useEffect, useState } from 'react';
import Tree from 'react-d3-tree';
import { Node } from '../utils/d3/interfaces/Node';

interface RoadmapProps {
  data: Node[];
}

export default function Roadmap({ data }: RoadmapProps) {
  const [isMounted, setIsMounted] = useState(false);

  useEffect(() => {
    setIsMounted(true);
  }, []);

  if (!isMounted) return null;

  return (
    <section>
      <div id="treeWrapper" style={{ width: '80vw', height: '100vh', overflow: 'hidden', position: 'relative' }}>
        <Tree
          data={data}
          zoomable={true}
          scaleExtent={{ max: 1, min: 0.1 }}
          draggable={true}
          translate={{ x: 600, y: 100 }}
          orientation="vertical"
          pathFunc="step"
        />
      </div>
    </section>
  )
}

4. 检查版本兼容性

确保react-d3-tree版本支持React 18(Next.js 13基于React 18),升级到最新稳定版本:

npm update react-d3-tree
# 或
yarn upgrade react-d3-tree

5. 手动控制拖拽缩放状态(备选方案)

如果以上方法无效,可通过回调手动维护拖拽、缩放状态,确保交互逻辑稳定:

"use client"

import { useState } from 'react';
import Tree from 'react-d3-tree';
import { Node } from '../utils/d3/interfaces/Node';

interface RoadmapProps {
  data: Node[];
}

export default function Roadmap({ data }: RoadmapProps) {
  const [translate, setTranslate] = useState({ x: 600, y: 100 });
  const [scale, setScale] = useState(1);

  return (
    <section>
      <div id="treeWrapper" style={{ width: '80vw', height: '100vh', overflow: 'hidden', position: 'relative' }}>
        <Tree
          data={data}
          zoomable={true}
          scaleExtent={{ max: 1, min: 0.1 }}
          draggable={true}
          translate={translate}
          scale={scale}
          onZoom={({ scale: newScale }) => setScale(newScale)}
          onDrag={({ translate: newTranslate }) => setTranslate(newTranslate)}
          orientation="vertical"
          pathFunc="step"
        />
      </div>
    </section>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 16:02:15