
에러 상황
React 프로젝트에서 Chart.js를 사용해 API 데이터를 시각화하던 중,
🚨 Canvas is already in use. Chart with ID '0' must be destroyed before the canvas with ID 'myChart' can be reused.
에러 메시지가 발생했습니다.
이 에러는 Chart.js가 동일한 canvas 요소에서 여러 번 초기화되면서 발생하는 문제입니다. 특히 React의 useEffect 훅 내에서 Chart.js를 사용할 때, 컴포넌트가 리렌더링되거나 useEffect가 다시 실행될 때마다 차트가 중복으로 생성되어 이러한 에러가 발생하게 됩니다.
문제 해결을 위한 접근 방법
이 문제를 해결하기 위해, 먼저 새로운 차트를 생성하기 전에 기존의 차트를 명시적으로 파괴(destroy)해야 한다는 점을 깨달았습니다. 이를 구현하기 위해 몇 가지 수정을 거쳤습니다:
- Chart.js 객체를 전역 변수로 선언: useEffect 내에서 차트 객체(myChart)를 전역 변수로 선언하여 컴포넌트의 라이프사이클 전반에서 접근할 수 있도록 했습니다.
- Cleanup 함수 구현: useEffect에서 반환되는 cleanup 함수를 사용해 컴포넌트가 언마운트되거나 useEffect가 다시 실행되기 전에 기존의 차트를 파괴했습니다. 이를 통해 동일한 canvas 요소를 여러 번 사용하는 상황을 방지했습니다.
import React, { useEffect } from 'react';
import { Chart } from 'chart.js';
function App() {
useEffect(() => {
let myChart; // Chart.js 객체 선언
const OPEN_API = "https://api.open-meteo.com/v1/forecast?latitude=37.566&longitude=126.9784&hourly=temperature_2m";
const draw = (res) => {
const opt = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric'
};
res.hourly.time = res.hourly.time.map(e => {
return new Intl.DateTimeFormat("ko-KR", opt).format(new Date(e));
});
const data = {
labels: res.hourly.time,
datasets: [{
label: '서울의 온도차트',
data: res.hourly.temperature_2m,
borderColor: 'rgb(255,99,132)',
backgroundColor: 'rgba(255,99,132,0.5)',
pointStyle: 'circle',
pointRadius: 10,
pointHoverRadius: 15,
}]
};
const ctx = document.getElementById('myChart').getContext('2d');
// 기존 차트 파괴 후 새 차트 생성
if (myChart) {
myChart.destroy();
}
myChart = new Chart(ctx, {
type: 'line',
data: data
});
};
const fetchData = async () => {
const ret = await fetch(OPEN_API).then(res => res.json());
draw(ret);
};
fetchData();
// cleanup 함수 반환: 컴포넌트가 언마운트될 때 또는 useEffect가 다시 실행되기 전에 실행됩니다.
return () => {
if (myChart) {
myChart.destroy();
}
};
}, []);
return (
<div style={{width: '100%', height: '100vh'}}>
<canvas id="myChart" width="400" height="400"></canvas>
</div>
);
}
export default App;
버전 호환성 문제와 해결
위의 수정에도 불구하고, 여전히 에러가 발생하는 상황이 있었습니다. 이 문제를 파악한 결과, Chart.js의 특정 버전(특히 최신 버전)이 React와의 호환성 문제를 일으킬 수 있다는 사실을 알게 되었습니다.
npm i chart.js@2.9.4 명령어를 통해 Chart.js의 버전을 2.9.4로 다운그레이드한 후, 문제없이 차트가 정상적으로 렌더링되는 것을 확인할 수 있었습니다.
배운 점 및 느낀 점
이번 트러블슈팅을 통해 다음과 같은 중요한 점들을 배울 수 있었습니다.
- 컴포넌트 라이프사이클 관리: React에서 외부 라이브러리를 사용할 때는 컴포넌트의 라이프사이클을 잘 관리하는 것이 중요합니다. 특히, 반복적으로 초기화되거나 리렌더링되는 리소스의 경우에는 명시적인 정리가 필요하다는 것을 깨달았습니다.
- 호환성 문제 인식: 외부 라이브러리의 버전이 중요하며, 최신 버전이 항상 안정적이지 않을 수 있다는 점을 경험했습니다. 버전 간의 호환성을 신중히 고려해야 한다는 것을 배웠습니다.
- 디버깅과 문제 해결 과정의 중요성: 에러 메시지를 정확히 이해하고, 문제의 원인을 단계적으로 파악하여 해결하는 과정이 얼마나 중요한지 다시금 느끼게 되었습니다.
이번 경험을 통해, 더 나은 코드 작성과 디버깅 능력을 기를 수 있었으며, 앞으로 유사한 문제를 더 빠르고 효율적으로 해결할 수 있을 것이라 생각합니다.
'트러블슈팅' 카테고리의 다른 글
[Prisma] 카테고리와 옵션 데이터의 중복 및 관리 문제 (0) | 2024.11.01 |
---|---|
[error msg] A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. (0) | 2024.09.22 |
TypeError: Cannot read properties of undefined (reading 'length') (0) | 2024.08.01 |
CORS Error를 만나다 (0) | 2024.07.25 |
Button 무한 클릭 시 api 호출 막기 (0) | 2024.07.23 |