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

React17项目使用D3 v7实现切换数据饼图时图表不显示求助

问题修复说明

你的代码存在4个核心问题导致饼图无法渲染:

  • useEffect未添加空依赖数组,组件每次渲染都会重复执行draw方法,无限新增svg节点,且初始执行d3选择器时目标DOM还未挂载完成,无法选中.PieChart容器
  • 按钮的onClick事件直接执行了update函数而非传递函数引用,导致渲染时立即触发update而非点击时触发
  • 存储平移到中心的<g>节点的引用未保存,后续绘制的饼图path没有挂载到正确的节点下,位置偏移超出可视区域
  • d3.pie的排序回调错误访问a.key属性,实际应该访问a[0]获取分组键名
修正后的完整代码
import * as d3 from 'd3'
import * as React from 'react'
import { useState, useEffect, useRef } from 'react'

const PieChart = (props) => {
    // 用useRef保存容器和d3元素引用,避免重复创建
    const containerRef = useRef(null)
    const gRef = useRef(null)

    // 只在组件挂载完成后执行一次draw
    useEffect(() => {
      draw()
    }, []);

    // 配置参数
    const width = 450, height = 450, margin = 40;
    const radius = Math.min(width, height) / 2 - margin;
    const color = d3.scaleOrdinal()
      .domain(["a", "b", "c", "d", "e", "f"])
      .range(d3.schemeDark2);
    
    const data1 = {a: 9, b: 20, c:30, d:8, e:12}
    const data2 = {a: 6, b: 16, c:20, d:14, e:19, f:12}

    const update = (dataType) => {
        const data = dataType === "data1" ? data1 : data2;
        const pie = d3.pie()
          .value(d => d[1])
          .sort((a, b) => d3.ascending(a[0], b[0]))
        const data_ready = pie(Object.entries(data))
        const arcGenerator = d3.arc().innerRadius(0).outerRadius(radius)

        // 从保存的g节点下选择path
        const u = d3.select(gRef.current)
          .selectAll("path")
          .data(data_ready)

        u.join('path')
          .transition()
          .duration(1000)
          .attr('d', arcGenerator)
          .attr('fill', d => color(d.data[0]))
          .attr("stroke", "white")
          .style("stroke-width", "2px")
          .style("opacity", 1)
    }
    
    const draw = () => {
        // 从ref获取容器,避免选择器命中其他页面同名节点
        const svg = d3.select(containerRef.current)
          .select(".PieChart")
          .append("svg")
          .attr("width", width)
          .attr("height", height)
        
        // 保存g节点引用
        gRef.current = svg.append("g")
          .attr("transform", `translate(${width/2}, ${height/2})`).node()

        update("data1")
    };
    

    return <div ref={containerRef} >
            {/* onClick传递函数引用,避免立即执行 */}
            <button onClick={() => update("data1")}>Data 1</button>
            <button onClick={() => update("data2")}>Data 2</button> 
            <div className="PieChart" /> 
        </div>
}

export default PieChart

内容的提问来源于stack exchange,提问作者Bill Software Engineer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 03:36:01