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

使用react-d3-tree+TypeScript时nodeSvgShape等属性不被识别

react-d3-tree属性无法识别、TS报错/JSX无法渲染问题解决

问题详情

  • 使用react-d3-tree的<Tree>组件时,nodeSvgShape、nodeLabelComponent、allowForeignObjects等官方文档标注的属性无法被TypeScript识别,触发类型错误
  • 已确认所有依赖为最新版本,尝试过切换不同版本的react-d3-tree,问题未解决
  • 将文件后缀从.tsx改为.jsx后,控制台类型错误消失,但Tree组件完全无法渲染

提供的代码(TreeCanvas.tsx)

/* eslint-disable react-hooks/exhaustive-deps */
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import Tree from 'react-d3-tree';
import './Nodes.css';

const treeData1 = {
  name: 'Family Title',
  className: 'node',
  children: [
    {
      name: 'Child 1',
      className: 'node',
      children: [
        {
          name: 'Grandchild 1',
          className: 'node',
        },
        {
          name: 'Grandchild 2',
          className: 'node',
        },
      ],
    },
    {
      name: 'Child 2',
      className: 'node',
      children: [
        {
          name: 'Grandchild 3',
          className: 'node',
        },
        {
          name: 'Grandchild 4',
          className: 'node',
        },
      ],
    },
  ],
};


const path = {
  pathFunc: (linkDatum: any, orientation: any) => {
    const { source, target } = linkDatum;
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const x = orientation === 'vertical' ? source.x : source.y;
    const y = orientation === 'vertical' ? target.y : target.x;
    const deltaX = Math.abs(source.x - target.x);
    const deltaY = Math.abs(source.y - target.y);
    const radius = Math.min(deltaX, deltaY) / 2;
    const offsetY = y > source.y ? radius : -radius;
    return `M${source.x},${source.y} V${y + offsetY} H${target.x}`;
  },
};



const TreeCanvas = () => {
  const ref = useRef<HTMLDivElement>(null); // set the type of ref to HTMLDivElement

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [numbers, setNumbers] = useState([]);

  const [width, setWidth] = useState(0);
  const [height, setHeight] = useState(0);

  useLayoutEffect(() => {
    if (ref.current) { // make sure that ref.current is not null before accessing clientWidth and clientHeight
      setWidth(ref.current.clientWidth);
      setHeight(ref.current.clientHeight);
    }
  }, [numbers, ref.current]);

  useEffect(() => {
    function handleWindowResize() {
      if (ref.current) { // make sure that ref.current is not null before accessing clientWidth and clientHeight
        setWidth(ref.current.clientWidth);
        setHeight(ref.current.clientHeight);
      }
    }

    window.addEventListener('resize', handleWindowResize);

    return () => {
      window.removeEventListener('resize', handleWindowResize);
    };
  }, [ref.current]);

  
  const svgSquare = {
    shape: 'rect',
    shapeProps: {
      width: 20,
      height: 20,
      x: -10,
      y: -10,
    }
  }

  const MyTree = ({ data }: any) => (
    
    <Tree
      data={data}
      orientation="vertical"
      translate={{ x: width / 2.35, y: height / 4 }}
      pathFunc={path.pathFunc}
      nodeSvgShape={svgSquare}
    />
  );

  return (
    <div id="treeCanvas" ref={ref}>
      <MyTree data={treeData1} />
    </div>
  );
};

export default TreeCanvas;

解决方案

1. 修复TypeScript属性识别问题

原因

react-d3-tree的官方类型定义包@types/react-d3-tree可能未同步更新所有属性,导致TypeScript无法识别这些配置项。

解决方法

  • 安装匹配版本的类型包:确保@types/react-d3-tree版本与react-d3-tree主包版本一致,执行命令:
npm install @types/react-d3-tree@<你的react-d3-tree版本号> --save-dev
  • 扩展类型接口:如果类型包确实缺失属性,可以手动扩展TreeProps接口,在项目中添加以下代码:
// 可以放在TreeCanvas.tsx顶部,或者单独的类型声明文件中
import { TreeProps } from 'react-d3-tree';

declare module 'react-d3-tree' {
  interface TreeProps {
    nodeSvgShape?: {
      shape: string;
      shapeProps: Record<string, any>;
    };
    nodeLabelComponent?: React.FC<any>;
    allowForeignObjects?: boolean;
  }
}
  • 临时忽略类型错误:如果需要快速验证功能,可以在属性前添加// @ts-ignore注释(不推荐长期使用):
<Tree
  data={data}
  orientation="vertical"
  translate={{ x: width / 2.35, y: height / 4 }}
  pathFunc={path.pathFunc}
  // @ts-ignore
  nodeSvgShape={svgSquare}
/>

2. 修复JSX下组件无法渲染问题

原因

组件初始化时width和height为0,Tree组件没有可用的渲染尺寸,导致无法生成SVG内容。同时,依赖项中直接使用ref.current会导致React钩子依赖判断异常,尺寸更新逻辑失效。

解决方法

  • 给容器设置默认尺寸:在Nodes.css中添加容器样式,确保初始有可用尺寸:
#treeCanvas {
  width: 100%;
  height: 100vh;
  min-width: 800px;
  min-height: 600px;
}
  • 优化尺寸状态初始化:避免初始值为0,直接获取容器初始尺寸或设置默认值:
const TreeCanvas = () => {
  const ref = useRef<HTMLDivElement>(null);
  // 初始化时设置默认尺寸,确保Tree有渲染空间
  const [width, setWidth] = useState(ref.current?.clientWidth || 800);
  const [height, setHeight] = useState(ref.current?.clientHeight || 600);
  
  // ...其余代码
};
  • 修正钩子依赖项:将ref.current替换为ref作为依赖(ref本身是稳定引用,ref.current变化不会触发依赖更新):
useLayoutEffect(() => {
  const updateSize = () => {
    if (ref.current) {
      setWidth(ref.current.clientWidth);
      setHeight(ref.current.clientHeight);
    }
  };
  updateSize();
}, [numbers, ref]); // 用ref代替ref.current

useEffect(() => {
  function handleWindowResize() {
    if (ref.current) {
      setWidth(ref.current.clientWidth);
      setHeight(ref.current.clientHeight);
    }
  }

  window.addEventListener('resize', handleWindowResize);
  return () => window.removeEventListener('resize', handleWindowResize);
}, [ref]); // 用ref代替ref.current
  • 添加渲染时机判断:确保尺寸有效时再渲染Tree组件:
const MyTree = ({ data }: any) => {
  // 尺寸为0时不渲染,避免无效渲染
  if (width === 0 || height === 0) return null;
  
  return (
    <Tree
      data={data}
      orientation="vertical"
      translate={{ x: width / 2.35, y: height / 4 }}
      pathFunc={path.pathFunc}
      nodeSvgShape={svgSquare}
    />
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:03:08