React动态新增Chart.js图表报Canvas已占用错误修复
报错原因
这个报错和你已经渲染好的存量图表完全无关,不需要销毁任何已正常展示的图表就能修复。
核心触发原因是你动态循环渲染新增Chart组件时,没有给列表项加唯一key属性,React做虚拟DOM对比时会错误复用之前已经绑定过Chart实例的canvas节点,Chart.js检测到同一个canvas DOM已经被初始化过,就会抛出canvas被占用的错误。
另外你代码里JSX部分的// chart test code写法不对,JSX里不会把这种写法识别为注释,会直接把文本渲染到页面上。
修复方法
只需要做两处调整:
- 给动态循环生成的每一个图表项绑定全局唯一的
key,不要用数组下标当key,避免React错误复用canvas节点 - 修正JSX的注释写法,避免无关文本渲染
修复后代码
import { Chart } from 'react-chartjs-2'; import { useState } from 'react'; // 提前注册用到的Chart.js组件,避免报元素未注册错误 import { Chart as ChartJS, LineElement, BarElement, PointElement, LinearScale, CategoryScale, Title, Tooltip, Legend, } from 'chart.js'; ChartJS.register( LineElement, BarElement, PointElement, LinearScale, CategoryScale, Title, Tooltip, Legend ); const Main = () => { // 存储新增图表配置,每个配置带唯一id作为渲染key const [count, setCount] = useState([]); const addWidget = () => { const newChart = { id: Date.now(), // 简单场景用时间戳做唯一id即可,复杂场景可替换为uuid config: { labels: ['1', '2', '3', '4', '5', '6', '7' , '8', '9','10'], datasets: [ { type: 'line', label: 'Dataset 1', borderColor: 'rgb(54, 162, 235)', borderWidth: 2, data: [30, 9, 24, 50,-20,20, 17, 45, 49], } ], } } setCount([...count, newChart]); } // 替换成你自己项目里已有的配置 const Line_data1 = {}; const Bar_data = {}; const options = {}; const Bar_mutilLabel_options = {}; return ( <div> {/* chart test code */} <Chart data={Line_data1} options={options} style={{ position: "relative"}}/> <Chart data={Bar_data} options={Bar_mutilLabel_options} style={{ position: "relative"}}/> {count.map(el => ( <div key={el.id}> <Chart style={{width:'10%'}} options={options} data={el.config}/> </div> ))} <button onClick={addWidget}> Click me </button> </div> ) }
注意事项
- 不要用数组下标作为列表渲染的key:后续如果做图表删除、插入排序操作,下标变动还是会导致节点错误复用,用每个图表项独立的唯一id当key是最稳妥的方案。
- 只有当你要替换同一个canvas位置的图表、或者卸载图表组件时,才需要手动调用
chartInstance.destroy()销毁实例,你现在是新增独立图表的场景,完全不需要销毁已有的图表实例。 - 如果你是手动封装Chart组件而非使用react-chartjs-2,记得在
useEffect的清理函数里销毁当前组件对应的图表实例,避免组件卸载后内存残留,但这个逻辑和你现在的报错无关。
内容的提问来源于stack exchange,提问作者gavi Su
相关产品推荐
相关产品推荐

