react-chartjs-2中category scale注册失败与Canvas复用报错求助
解决 react-chartjs-2 + Chart.js 中的两个常见错误
一、"category" is not a registered scale 错误
你已手动注册CategoryScale但仍报错,可从以下几个方向排查解决:
1. 调整注册时机,全局单次注册
将Chart.register代码移至React应用的入口文件(如index.js或App.js),而非单个组件文件内。若在组件中注册,多次渲染时可能引发注册异常或实例共享问题。
示例(入口文件):
import { BarElement, CategoryScale, Chart, Legend, LinearScale, Title, Tooltip } from "chart.js"; // 全局注册所需组件,仅执行一次 Chart.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);
2. 显式指定坐标轴类型
在options中明确配置x轴类型为category,避免Chart.js自动推断出错:
const options = { responsive: true, scales: { x: { type: 'category', // 显式声明x轴类型 }, }, plugins: { legend: { position: 'top' }, title: { display: true, text: 'A title' }, }, };
3. 校验依赖版本兼容性
确认react-chartjs-2@5.2.0与chart.js@4.3.0无版本冲突,可删除依赖文件后重新安装:
rm -rf node_modules package-lock.json npm install
二、Canvas is already in use. Chart with ID '0' must be destroyed before the canvas with ID '' can be reused. 错误
该错误源于组件重渲染时旧Chart实例未被正确销毁,导致canvas被重复绑定,可通过以下方式解决:
1. 给Bar组件添加唯一key
当data或options频繁变化时,为<Bar>组件添加唯一key,强制React重建组件实例,避免复用旧canvas:
return <Bar key={JSON.stringify(data)} options={options} data={data}/>;
(若数据量较大,JSON.stringify性能不足,可改用递增计数器等状态变量作为key)
2. 用useRef手动管理Chart实例
通过useRef保存Chart实例,在组件卸载或数据更新前手动销毁旧实例:
import React, { useEffect, useRef } from "react" import { Bar } from "react-chartjs-2" import { BarElement, CategoryScale, Chart, Legend, LinearScale, Title, Tooltip } from "chart.js" Chart.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend) export default function Test() { const chartRef = useRef(null); const options = { /* 你的配置 */ }; const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; const data = { /* 你的数据 */ }; useEffect(() => { // 组件卸载时销毁Chart实例 return () => { if (chartRef.current) { chartRef.current.destroy(); } }; }, []); return <Bar ref={chartRef} options={options} data={data}/>; }
3. 减少不必要的重渲染
检查父组件是否频繁触发Test组件重渲染,比如传递的props是否每次都生成新引用(如对象、数组)。可使用useMemo缓存options和data:
const options = useMemo(() => ({ responsive: true, scales: { x: { type: 'category' } }, plugins: { legend: { position: 'top' }, title: { display: true, text: 'A title' }, }, }), []); const data = useMemo(() => ({ labels, datasets: [ { label: 'Dataset 1', data: labels.map(() => Math.random()), backgroundColor: 'rgba(255, 99, 132, 0.5)', }, { label: 'Dataset 2', data: labels.map(() => Math.random()), backgroundColor: 'rgba(53, 162, 235, 0.5)', }, ], }), [labels]);
内容的提问来源于stack exchange,提问作者Alexandre Gaubil
相关产品推荐
相关产品推荐

