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

React TypeScript中通过ID访问HTML元素是否合规?Chart.js实例化报错求解

在React TypeScript中集成Chart.js的常见问题与解决

问题背景

之前任职公司明确要求,在React TypeScript中禁止使用getElementById这类直接操作DOM的方式。我现在集成Chart.js时,最初选择用useRef Hook来配置图表,但控制台抛出错误:Failed to create chart: can't acquire context from the given item,图表数据无法加载。我怀疑是不是必须通过ID获取canvas才能正确实例化,想确认这种场景下useRef的用法是否合规。

错误信息

Failed to create chart: can't acquire context from the given item

相关代码

useEffect逻辑代码

useEffect(() => {
  chart = new Chart(chartRef.current, {
    type: "bar",
    data: {
      labels: labelsArray.map((label) => {
        const date = new Date(label);
        // 月份是0索引,加1修正
        return date.getUTCMonth() + 1 + "/" + date.getUTCDate();
      }),
      datasets: [
        {
          data: valuesArray,
          backgroundColor: "#1565C0",
          borderRadius: 6,
        },
      ],
    },
    options: {
      interaction: { mode: "index" },
      onHover: (event, chartElement) => {
        const target = event.native.target;
        (target as HTMLInputElement).style.cursor = chartElement[0]
          ? "pointer"
          : "default";
      },
      plugins: {
        tooltip: {
          mode: "index",
          enabled: true,
        },
        title: {
          display: true,
          text: "Daily Usage Past 30 Days",
          align: "start",
          fullSize: true,
          font: {
            size: 24,
          },
          padding: {
            bottom: 36,
          },
        },
      },
      scales: {
        x: {
          display: false,
        },
      },
      elements: {
        line: {
          borderJoinStyle: "round",
        },
      },
    },
  });
  return () => {
    chart.destroy();
  };
}, [labelsArray, valuesArray]);

组件模板代码

<div className="mt-80 ml-12 p-8 shadow-lg border-2 border-slate-100 rounded-xl items-center">
   <canvas id="chart" ref={chartRef}></canvas>
   <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</div>

Chart.js官方说明

To create a chart, we need to instantiate the Chart class. To do this, we need to pass in the node, jQuery instance, or 2d context of the canvas of where we want to draw the chart.

解决方案与结论

  1. 优先使用useRef是合规且正确的做法,完全不需要用getElementById,你的技术方向没问题。

  2. 报错核心原因:

    • chartRef.current可能为null(组件未挂载/已卸载时触发useEffect);
    • 直接传入canvas节点时,Chart.js可能无法自动获取有效上下文;
    • 组件内嵌入的<script>标签加载时机不可控,可能导致Chart类未初始化完成就执行实例化代码。
  3. 具体修正步骤:

    • 给useRef指定明确的TS类型,避免null类型隐患:
      const chartRef = useRef<HTMLCanvasElement>(null);
      
    • 在useEffect中先校验canvas元素和上下文有效性,再实例化Chart:
      useEffect(() => {
        if (!chartRef.current) return;
        
        const ctx = chartRef.current.getContext('2d');
        if (!ctx) return;
        
        const chartInstance = new Chart(ctx, {
          // 你的图表配置内容
        });
        
        return () => chartInstance.destroy();
      }, [labelsArray, valuesArray]);
      
    • 移除组件内的<script>标签,改用npm管理Chart.js依赖:
      npm install chart.js
      
      在组件顶部导入:
      import Chart from 'chart.js/auto';
      
  4. 符合官方文档要求:通过useRef获取canvas节点后,提取其2d上下文传入Chart构造函数,完全符合文档中"传入canvas的2d context"的标准用法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:20:34