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
相关产品推荐
相关产品推荐

