Skip to content

[Bug]: Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused. #1037

Closed

Description

@Zaid-maker

Would you like to work on a fix?

  • Check this if you would like to implement a PR, we are more than happy to help you go through the process.

Current and expected behavior

Getting this error after upgrading to new version.

Reproduction

hmm

chart.js version

3.7.1

react-chartjs-2 version

4.1.0

Possible solution

No response

Activity

  1. dangreen commented on Apr 8, 2022

    @dangreen
    Collaborator

    @Zaid-maker Hi. Please provide reproduction, you can fork this codesandbox.

  2. Zaid-maker commented on Apr 8, 2022

    @Zaid-maker
    Author

    @Zaid-maker Hi. Please provide reproduction, you can fork this codesandbox.

    Hi, actually i dont know how to but i can show you my code where it uses chart and the errors too.

    import { Line } from "react-chartjs-2";
    
    <div
              className={styles.percent}
              style={{ color: coin.change < 0 ? "#ef4b09" : "green" }}
            >
              {coin.change}%
            </div>
  3. Zaid-maker commented on Apr 8, 2022

    @Zaid-maker
    Author

    i am using nextjs and its different from reactjs so i will make a sandbox for nextjs and will update you.

  4. Blademaster680 commented on Apr 25, 2022

    @Blademaster680

    Is there any update on this? I am getting the exact same issue with one of my dynamic graphs rendering it in a Functional component and not sure how to sort this out

  5. Arantiryo commented on Apr 25, 2022

    @Arantiryo
    Collaborator

    Hi @Blademaster680! I've had no luck trying to reproduce the issue. Would you please fork this codesandbox and replicate it?

  6. Blademaster680 commented on Apr 25, 2022

    @Blademaster680

    @Arantiryo Let me see what I can do and post the results here, I think its because my graph is dynamically updating from data that gets updated from the redux state. So it renders the graph and then gets the data to populate the graph (Reading from an API) and we have mutliple data points to change the graph data with

    EDIT: I might just add that this only started occuring when I updated to React 18.0 from React 17.0

  7. MartinP-C commented on May 10, 2022

    @MartinP-C

    I was getting this error (again with React 18.0.1, in Strict Mode)
    Removing Strict Mode stops the error (because Strict Mode double-invokes lifecycle functions when in dev mode? Hence re-use of canvas? https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects)

    However! Strict Mode wasn't the problem itself.
    I had not registered a Chart.JS component and the error being thrown ('"arc" is not a registered element') must have caused React to double-invoke and try to re-use the canvas.

    Fixing the registered element error also stopped "Canvas already in use" error.
    (Registering components: https://react-chartjs-2.js.org/docs/migration-to-v4#tree-shaking)

  8. Arantiryo commented on May 10, 2022

    @Arantiryo
    Collaborator

    Hey @MartinP-C 👋

    Thank you for the detailed explanation!

    I'll keep the issue open for now but it looks like the root cause is found and this can be marked as resolved.

  9. awsomesroka commented on May 20, 2022

    @awsomesroka

    Same here, change to react 18 (that changed APP rendering way) causes the canavas error.
    Non of above solution wordked :/

  10. Arantiryo commented on May 21, 2022

    @Arantiryo
    Collaborator

    Hi @awsomesroka

    Do you think you could create a minimal reproduction using this code sandbox example? Or if you're are using redux and think that might be causing the error, you could use this CRA template with redux and react-chartjs-2 as a starting point.

    Thank you!

  11. jefelewis commented on Jun 28, 2022

    @jefelewis
    import { useState, useRef } from 'react';
    import { Line } from 'react-chartjs-2';
    import 'chart.js/auto'; // ADD THIS
    
    export const ChartLine = (): JSX.Element => {
      const ref = useRef();
    
      const data = {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
        datasets: [
          {
            label: 'First dataset',
            data: [33, 53, 85, 41, 44, 65],
            fill: true,
            backgroundColor: 'rgba(75,192,192,0.2)',
            borderColor: 'rgba(75,192,192,1)'
          },
          {
            label: 'Second dataset',
            data: [33, 25, 35, 51, 54, 76],
            fill: false,
            borderColor: '#742774',
          },
        ],
      };
    
      return <Line ref={ref} data={data} />
    };
  12. dinaAlsaid commented on Jul 27, 2022

    @dinaAlsaid

    I get this error when I use two charts in the same component.. this didn't happen with v3 or versions before react 18

  13. HernanGH commented on Sep 14, 2022

    @HernanGH

    Same error here

  14. dangreen commented on Sep 28, 2022

    @dangreen
    Collaborator

    Hi @dinaAlsaid @HernanGH ! We've had no luck trying to reproduce the issue. Would you please fork this codesandbox and replicate it?

    @jefelewis Is it the reproduction of the issue? Your example is perfectly working: https://codesandbox.io/s/jolly-pateu-wiuvn1?file=/App.tsx

  15. 10 remaining items

  16. bizzara commented on Jan 10, 2023

    @bizzara

    I faced the same issues with NextJs. I tried all these above solutions. it didn't work for me. Finally, I disabled the reactStrictMode in my next.config.js file and it worked.

    reactStrictMode: false

  17. rojvv commented on Mar 17, 2023

    @rojvv

    Please reopen this issue. I cannot set width/height when I import char.js/auto.

  18. ten4dinosaur commented on Apr 24, 2023

    @ten4dinosaur

    @jefelewis, For me, the chart only appears on the screen after i add this to my code.

    import 'chart.js/auto';

    I didn't need to use a ref.

    Started using this library today, ran into the same error. While debugging, I found that, this block of code:
    chart.tsx
    96: useEffect(() => {
    97: renderChart();
    98:
    99: return () => destroyChart();
    100: }, []);
    is executed several times, because an error occurs during the first render. As a result, several ChartJs instances are attached to the same canvas. The error on the first render is due to the lack of registration of *Scale and *Element components. import 'chart.js/auto'; registers all available components, so this fixes the error on first render.

    Please reopen this issue. I cannot set width/height when I import char.js/auto.

    This because of auto size feature in chartjs. Set responsive: false in options to disable it
    <Line options={{ responsive: false }} height={150} width={300} data={mockdata} />

  19. abir-25 commented on May 14, 2023

    @abir-25

    Thank you Brother

  20. BrandonArgel commented on Jun 16, 2023

    @BrandonArgel

    I had this problem because I was trying to create several charts directly in the same component, solved the issue with the following method:

    1. Create Chart.tsx compontent:
    import * as React from "react";
    import ChartJS from "chart.js/auto";
    import { Theme } from "@mui/material/styles";
    import { makeStyles } from "@mui/styles";
    import { buildChartConfig } from "@utils";
    import { Paper, Typography } from "@mui/material";
    
    type ChartsProps = {
    	data: any;
    	config: any;
    	title: string;
    	size?: number;
    };
    
    const useStyles = makeStyles((theme: Theme) => ({
    	root: {},
    	header: {},
    	title: {},
    	chart: {},
    	text: {},
    	canvas: {},
    }));
    
    export const Chart: React.FC<ChartsProps> = ({ data, config, title, size = 300 }) => {
    	const chartId = React.useId();
    	const classes = useStyles();
    	const chartError = !(data && data.length > 0);
    
    	React.useEffect(() => {
    		if (!data.length) return;
    		const ctx = document.getElementById(chartId) as HTMLCanvasElement;
    		const _config = {
    			...config,
    		};
    
    		const chart = new ChartJS(ctx, buildChartConfig(_config));
    
    		return () => {
    			chart.destroy();
    		};
    	}, [data, config, chartId]);
    
    	return (
    		<Paper className={classes.root}>
    			<header className={classes.header}>
    				<Typography variant="h1" className={classes.title}>
    					{title}
    				</Typography>
    			</header>
    			<div className={classes.chart}>
    				{chartError && <p className={classes.text}>Nothing to see here!</p>}
    				<canvas id={chartId} width={size} height={size} className={classes.canvas} />
    			</div>
    		</Paper>
    	);
    };
    1. Calling this new component:
    import * as React from "react";
    import { Theme } from "@mui/material/styles";
    import { makeStyles } from "@mui/styles";
    import { Chart } from "@components";
    import { languageColors, backgroundColor, borderColor } from "@utils";
    import { LanguageModel, RepositoryModel } from "@models";
    
    type ChartsProps = {
    	languages: LanguageModel[];
    	repositories: RepositoryModel[];
    };
    
    const useStyles = makeStyles((theme: Theme) => ({
    	root: {},
    }));
    
    export const Charts: React.FC<ChartsProps> = ({ languages, repositories }) => {
    	const classes = useStyles();
    	// Chart data
    	const [languageData, setLanguageData] = React.useState<number[]>([]);
    	const [starsData, setStarsData] = React.useState<number[]>([]);
    	const [starsPerLangData, setStarsPerLangData] = React.useState<number[]>([]);
    	const [languageConfig, setLanguageConfig] = React.useState<any>({});
    	const [starsConfig, setStarsConfig] = React.useState<any>({});
    	const [starsPerLangConfig, setStarsPerLangConfig] = React.useState<any>({});
    
    	React.useEffect(() => {
    		if (languages!.length && repositories.length) {
    			// Example: create Top Languages chart
    			const initLangChart = () => {
    				const labels = languages && languages.map((lang) => lang.label);
    				const data = languages && languages.map((lang) => lang.value);
    
    				setLanguageData(data);
    
    				if (data!.length > 0) {
    					const backgroundColor =
    						languages &&
    						languages.map(
    							({ color }) => `#${color.length > 4 ? color.slice(1) : color.slice(1).repeat(2)}B3`
    						);
    					const borderColor = languages && languages.map((lang) => `${lang.color}`);
    					const chartType = "pie";
    					const axes = false;
    					const legend = true;
    					const config = { chartType, labels, data, backgroundColor, borderColor, axes, legend };
    
    					setLanguageConfig(config);
    				}
    			};
    
    			const initStarChart = () => {
    				// Logic to get data and config for each chart
    			};
    
    			const initStarsPerLangChart = () => {
    				// Logic to get data and config for each chart
    			};
    
    			initLangChart();
    			initStarChart();
    			initStarsPerLangChart();
    		}
    	}, [languages, repositories]);
    
    	return (
    		<div className={classes.root}>
    			<Chart title={"Top Languages"} data={languageData} config={languageConfig} />
    			<Chart title={"Most Starred"} data={starsData} config={starsConfig} />
    			<Chart title={"Stars per Language"} data={starsPerLangData} config={starsPerLangConfig} />
    		</div>
    	);
    };

    Hope it helps. :)

  21. lazarevkristijan commented on Sep 6, 2023

    @lazarevkristijan

    This is the new way to do things guys! V4 of chart-js has new syntax. This is an extremely simple example just for you to see how it works, then modify it!

    import "chart.js/auto"
    import { Chart } from "react-chartjs-2"
    
    const LineChart = () => {
      const data = {
        labels: ["Jan", "Feb", "Mar", "Apr", "May"],
        datasets: [
          {
            label: "Sales foor 2020 (M)",
            data: [3, 2, 2, 3, 5],
          },
        ],
      }
      return (
        <Chart
          type="line"
          data={data}
        />
      )
    }
    
    export default LineChart
    
  22. biratdevpoudel commented on Nov 23, 2023

    @biratdevpoudel
    import { useState, useRef } from 'react';
    import { Line } from 'react-chartjs-2';
    import 'chart.js/auto'; // ADD THIS
    
    export const ChartLine = (): JSX.Element => {
      const ref = useRef();
    
      const data = {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
        datasets: [
          {
            label: 'First dataset',
            data: [33, 53, 85, 41, 44, 65],
            fill: true,
            backgroundColor: 'rgba(75,192,192,0.2)',
            borderColor: 'rgba(75,192,192,1)'
          },
          {
            label: 'Second dataset',
            data: [33, 25, 35, 51, 54, 76],
            fill: false,
            borderColor: '#742774',
          },
        ],
      };
    
      return <Line ref={ref} data={data} />
    };

    This worked for me.

  23. lhz516 commented on Nov 28, 2023

    @lhz516

    Using chart.js/auto increases the bundle size.

    My solution is not using react-chartjs-2 and do:

    import {
      Chart,
      CategoryScale,
      ...
    } from 'chart.js';
    
    Chart.register(CategoryScale); // and other registration stuff
    
    const MyChart = ({ record }) => {
      const ctx = React.useRef(null);
      useEffect(() => {
        const chart = new Chart(ctx.current, {
           ...
        });
      };
      return () => {
          // need cleanup because React runs useEffect callback twice in dev env
          chart.destroy();
        };
    }, []);
    return (
        <div>
          <canvas ref={ctx} />
        </div>
      );
    }
  24. captainkapnap commented on Mar 9, 2024

    @captainkapnap

    I had same issue. Two nearly identical charts, one would result in Canvas is already in use error. Charts are located in a NextUI modal. If I were to Open Modal, generate chart, close modal, re-open modal, error would show up for one type of chart and not the other.

    Removing the maintainAspectRatio: true, in the options fixed everything.

  25. Dharld commented on Apr 6, 2024

    @Dharld
    import { useState, useRef } from 'react';
    import { Line } from 'react-chartjs-2';
    import 'chart.js/auto'; // ADD THIS
    
    export const ChartLine = (): JSX.Element => {
      const ref = useRef();
    
      const data = {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
        datasets: [
          {
            label: 'First dataset',
            data: [33, 53, 85, 41, 44, 65],
            fill: true,
            backgroundColor: 'rgba(75,192,192,0.2)',
            borderColor: 'rgba(75,192,192,1)'
          },
          {
            label: 'Second dataset',
            data: [33, 25, 35, 51, 54, 76],
            fill: false,
            borderColor: '#742774',
          },
        ],
      };
    
      return <Line ref={ref} data={data} />
    };

    Worked for me. Thanks

  26. dipesh-m12 commented on May 29, 2024

    @dipesh-m12

    @jefelewis, For me, the chart only appears on the screen after i add this to my code.

    import 'chart.js/auto';

    I didn't need to use a ref.

    Worked for me too

  27. AndreiShenets commented on Oct 24, 2024

    @AndreiShenets

    I see such message when an error is raised inside of any function like color: function() {...} or backgroundColor: function() {...} within ChartData definition when there is no element. So check for errors inside of your code they might result to the same message.

  28. MartyOfMCA commented on Dec 24, 2024

    @MartyOfMCA

    Should anyone find themselves in this same problem now, kindly have a read at the docs on https://react-chartjs-2-two.vercel.app/

  29. afuahsekyiwaaadusei commented on Jan 8, 2025

    @afuahsekyiwaaadusei

    If none of the provided answers worked, try cleaning up the Chart instances on component unmount. That worked for me.

    import { useEffect } from "react";
    import {Chart as ChartJs}  from "chart.js/auto";
    import {Line} from "react-chartjs-2";
    
    const LineChart =  () => {
        useEffect(()=> {
            return () => {
                // Cleanup all Chart.js instances on unmount
                Object.keys(ChartJs.instances).forEach((key) => {
                  ChartJs.instances[key].destroy();
                });
            };
        }, []);
    
    
        const data = {
            labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
            datasets: [
            {
                label: 'First dataset',
                data: [33, 53, 85, 41, 44, 65],
                fill: true,
                backgroundColor: 'rgba(75,192,192,0.2)',
                borderColor: 'rgba(75,192,192,1)'
            },
            {
                label: 'Second dataset',
                data: [33, 25, 35, 51, 54, 76],
                fill: false,
                borderColor: '#742774',
            },
            ],
        };
        
        return <Line data={data} />
    }
    export default LineChart;
    
  30. HardikChoudhary24 commented on Nov 8, 2025

    @HardikChoudhary24

    I see such message when an error is raised inside of any function like color: function() {...} or backgroundColor: function() {...} within ChartData definition when there is no element. So check for errors inside of your code they might result to the same message.

    This is what worked for me. In nextjs whenever we get this error Error: Canvas is already in use. Chart with ID '9' must be destroyed before the canvas with ID '' can be reused. we will always have one more error arising from inside the other functions like color, backgroundColor, etc. Fixing that issue will also resolve this particular error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions