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

React+D3图表无法渲染Context映射数据,静态数据正常

问题描述

我是React和D3的新手,尝试在带有背景图的网格(x/y轴)上展示每条记录的小图标数据。使用静态数据gcs时,D3图表可正常工作;但从CohortContext中过滤映射得到的goalCohorts数据无法在图表上显示。我怀疑是D3渲染早于数据返回的时序问题,尝试用async包裹useEffect但未解决。控制台显示goalCohorts数据与静态数据结构一致,使用React v18.1、D3 v7.8,相关代码如下:

import React, { useEffect, useContext } from "react"
import * as d3 from "d3"
import logo from '../../assets/images//charts/360Chart.svg'
import CohortContext from "../../utility/context/cohort/cohort-context"
import Saboteur from '../../assets/images/charts/chartBubbleKey.svg'

function ChartData({ goal }) {
    const gcs = [
        {
            chartAsset: Saboteur,
            xCoordinates: 200,
            yCoordinates: 300
        },
        {
            chartAsset: Saboteur,
            xCoordinates: 150,
            yCoordinates: 150
        }
    ]
    console.log(gcs)
    const width = 800
    const height = 800
    const { cohorts } = useContext(CohortContext) 
    
    useEffect(() => {
        //Retrieve the Goal data from the useContext
        const fetchData = async () => {
            const goalCohorts = cohorts
                            .filter(records => records.goalId === goal.goalId)
                            .map((records) => {
                                return {
                                chartAsset: Saboteur,
                                xCoordinates: records.xcoordinates,
                                yCoordinates: records.ycoordinates
                                }
                            })

        console.log('goal cohorts for Chart :', goalCohorts)

        const svg = d3
            .select("#svgcontainer")
            .append("svg")
            .attr("width", width)
            .attr("height", height)

        //background Chart
        svg
            .append("svg:image")
            .attr("xlink:href", () => logo)
            .attr("width", 580)
            .attr("height", 580)
            .attr("x", 110)
            .attr("y", 20)

        // Add in the data for the chart data
        const g = svg
            .selectAll("g")
            .append("g")
            .data(goalCohorts)  // works if I use .data(gcs)
            .enter()

        g.append("svg:image")
            .attr("xlink:href", (data) => data.chartAsset)
            .attr("width", 50)
            .attr("height", 50)
            .attr("x", (data) => data.xCoordinates)
            .attr("y", (data) => data.yCoordinates)
        }
        fetchData()
    }, [])

    return (
        < div className="App" >
            <div id="svgcontainer"></div>
        < /div >
    )
}

export default ChartData
问题原因及修复方案
  • 依赖项缺失导致useEffect未触发更新:你的useEffect依赖数组为空,初始渲染时cohorts可能还未从Context中加载完成,导致goalCohorts为空;后续cohorts或goal更新时,useEffect也不会重新执行生成新图表。
    修复:将cohorts和goal.goalId加入依赖数组:

    useEffect(() => {
      // ... 原有逻辑
    }, [cohorts, goal.goalId])
    
  • D3数据绑定顺序错误:你先执行.append("g")再绑定数据,这会把数据绑定到一个空的<g>元素上,而非基于数据创建新元素。正确流程是先选择元素、绑定数据、进入阶段,再创建元素。另外,给选择器加类名避免选中背景图相关元素:
    修复:调整数据绑定代码:

    // 正确的数据绑定流程
    const g = svg
      .selectAll("g.chart-item") // 用类名精准选择
      .data(goalCohorts)
      .enter()
      .append("g") // 进入阶段后创建对应数量的g元素
    
    g.append("svg:image")
      .attr("href", (data) => data.chartAsset) // D3 v7推荐使用href替代xlink:href
      .attr("width", 50)
      .attr("height", 50)
      .attr("x", (data) => data.xCoordinates)
      .attr("y", (data) => data.yCoordinates)
    
  • 重复创建SVG元素:每次useEffect执行都会往容器追加新SVG,旧图表残留且新图表可能被覆盖。需要在创建前清空容器:
    修复:创建SVG前清空容器内容:

    const svgContainer = d3.select("#svgcontainer");
    svgContainer.html(""); // 清空原有内容
    
    const svg = svgContainer
      .append("svg")
      .attr("width", width)
      .attr("height", height);
    
  • 冗余的async函数:fetchData内没有异步操作,无需用async包裹,去掉后可避免不必要的异步时序问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 08:05:38