Подключение в проектах на React, Vue, Angular

Подключение Chart.js в современных фронтенд-фреймворках требует учета их реактивной модели, жизненного цикла компонентов и управления DOM-элементами <canvas>. В каждом из подходов — React, Vue и Angular — библиотека интегрируется через разные механизмы, но базовая логика остается общей: создание canvas-элемента, инициализация экземпляра графика, последующее обновление данных и корректное уничтожение экземпляра при размонтировании компонента.


Chart.js работает напрямую с Canvas API, поэтому ключевой точкой интеграции становится DOM-элемент <canvas>. В SPA-фреймворках важно учитывать:

  • инициализацию графика только после монтирования компонента;
  • хранение ссылки на экземпляр Chart для последующего обновления;
  • предотвращение повторной инициализации при ререндерах;
  • обязательное уничтожение экземпляра через destroy() при размонтировании.

Базовый жизненный цикл выглядит следующим образом:

  1. Создание canvas-элемента
  2. Получение DOM-ссылки
  3. Инициализация new Chart(ctx, config)
  4. Обновление через chart.data + chart.update()
  5. Очистка через chart.destroy()

Интеграция в React

В экосистеме React работа с Chart.js обычно строится через useRef и useEffect, поскольку прямой доступ к DOM ограничен декларативной моделью React.

Базовая реализация

import { useEffect, useRef } from "react";
import Chart from "chart.js/auto";

function LineChart() {
  const canvasRef = useRef(null);
  const chartRef = useRef(null);

  useEffect(() => {
    const ctx = canvasRef.current.getContext("2d");

    chartRef.current = new Chart(ctx, {
      type: "line",
      data: {
        labels: ["Jan", "Feb", "Mar", "Apr"],
        datasets: [
          {
            label: "Продажи",
            data: [12, 19, 3, 5],
            borderColor: "blue",
          },
        ],
      },
    });

    return () => {
      chartRef.current.destroy();
    };
  }, []);

  return <canvas ref={canvasRef} />;
}

Обновление данных

Обновление в React выполняется через изменение состояния и вызов update():

chartRef.current.data.datasets[0].data = [5, 10, 15, 20];
chartRef.current.update();

Особенности React-интеграции

  • useEffect заменяет lifecycle методы
  • useRef предотвращает повторное создание графика
  • strict mode может вызывать двойной рендер, требующий защиты от дублирования

Интеграция в Vue

В Vue.js работа с Chart.js обычно строится через onMounted и реактивные ref.

Vue 3 Composition API

<template>
  <canvas ref="canvas"></canvas>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import Chart from "chart.js/auto";

const canvas = ref(null);
let chartInstance = null;

onMounted(() => {
  const ctx = canvas.value.getContext("2d");

  chartInstance = new Chart(ctx, {
    type: "bar",
    data: {
      labels: ["A", "B", "C"],
      datasets: [
        {
          label: "Данные",
          data: [10, 20, 30],
          backgroundColor: "green",
        },
      ],
    },
  });
});

onBeforeUnmount(() => {
  if (chartInstance) {
    chartInstance.destroy();
  }
});
</script>

Реактивное обновление данных

Vue позволяет автоматически реагировать на изменения:

watch(data, (newVal) => {
  chartInstance.data.datasets[0].data = newVal;
  chartInstance.update();
});

Особенности Vue-интеграции

  • ref обеспечивает доступ к DOM
  • watch связывает реактивные данные и Chart.js
  • важно предотвращать повторную инициализацию при повторных рендерах

Интеграция в Angular

В Angular чаще используется комбинация ViewChild и жизненного цикла компонентов.

Базовая реализация

import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
import Chart from 'chart.js/auto';

@Component({
  selector: 'app-chart',
  template: `<canvas #canvas></canvas>`
})
export class ChartComponent implements AfterViewInit, OnDestroy {
  @ViewChild('canvas') canvas!: ElementRef<HTMLCanvasElement>;
  chart!: Chart;

  ngAfterViewInit() {
    const ctx = this.canvas.nativeElement.getContext('2d');

    this.chart = new Chart(ctx!, {
      type: 'pie',
      data: {
        labels: ['Red', 'Blue', 'Green'],
        datasets: [{
          data: [30, 40, 30]
        }]
      }
    });
  }

  ngOnDestroy() {
    if (this.chart) {
      this.chart.destroy();
    }
  }
}

Обновление данных

this.chart.data.datasets[0].data = [10, 20, 70];
this.chart.update();

Особенности Angular-интеграции

  • AfterViewInit гарантирует доступ к DOM
  • ViewChild используется для canvas-ссылки
  • строгая типизация упрощает контроль состояния графика
  • важно учитывать change detection при частых обновлениях

Управление экземпляром Chart.js в SPA

Во всех фреймворках сохраняется единая архитектурная модель управления:

Хранение экземпляра

  • React: useRef
  • Vue: локальная переменная или shallowRef
  • Angular: свойство класса компонента

Обновление данных

Обновление происходит императивно:

  • изменение chart.data
  • вызов chart.update()

Уничтожение

Критически важный этап:

  • предотвращение утечек памяти
  • очистка event listeners
  • освобождение canvas контекста

Метод:

chart.destroy();

Работа с динамическими данными

При интеграции с API или потоковыми данными применяется следующий паттерн:

  1. получение данных
  2. нормализация под формат datasets
  3. обновление chart.data
  4. вызов update

Пример структуры данных:

{
  labels: ["x1", "x2"],
  datasets: [
    {
      label: "Метрика",
      data: [1, 2]
    }
  ]
}

Оптимизация производительности

При частых обновлениях данных в React, Vue и Angular учитываются следующие аспекты:

  • минимизация перерисовок canvas
  • пакетное обновление данных
  • использование requestAnimationFrame при анимациях
  • отключение лишних плагинов Chart.js
  • контроль глубины реактивности (Vue)

Типовые ошибки интеграции

  • повторная инициализация Chart при каждом рендере компонента
  • отсутствие destroy() при размонтировании
  • попытка доступа к canvas до его инициализации
  • конфликт реактивных обновлений и императивного API Chart.js
  • хранение экземпляра в состоянии вместо референса

Архитектурные паттерны

Обертка над Chart.js

Часто создается отдельный слой:

  • ChartService (Angular)
  • composable useChart (Vue)
  • custom hook useChart (React)

Он инкапсулирует:

  • создание графика
  • обновление данных
  • уничтожение экземпляра

Пример логики слоя

  • init(config)
  • update(data)
  • destroy()

Сравнение подходов интеграции

Фреймворк Основной механизм доступа к DOM Управление жизненным циклом
React useRef + useEffect хуки
Vue ref + lifecycle hooks onMounted / onUnmounted
Angular ViewChild AfterViewInit / OnDestroy

Использование Chart.js в рамках React, Vue и Angular строится вокруг единой императивной модели управления графиком, адаптированной под декларативные ограничения каждого фреймворка.