Библиотека визуализации данных Nivo строит графики поверх SVG или Canvas, и почти каждый компонент зависит от корректно рассчитанных размеров контейнера. Ошибка в определении ширины или высоты приводит к обрезанным осям, некорректному масштабированию и потере читаемости графика. Поэтому управление размерами — один из ключевых аспектов интеграции Nivo в интерфейсы на JavaScript.
Компоненты Nivo не предполагают, что размеры известны заранее. Вместо
этого используется модель, при которой график получает
width и height либо напрямую через props, либо
через вычисление размеров родительского контейнера.
Внутри экосистемы Nivo для этого применяется подход с измерением
DOM-элемента, основанный на ResizeObserver или аналогичных
механизмах. Это позволяет автоматически реагировать на изменения layout
без ручного пересчёта.
Хук useSize служит для динамического получения размеров
DOM-элемента. Он отслеживает изменения контейнера и возвращает
актуальные width и height, которые можно
передавать в компоненты графиков.
Основная идея заключается в привязке измерений к реальному DOM-узлу, а не к статическим значениям.
Ключевые особенности:
refТиповой сценарий включает привязку ref к контейнеру и
получение размеров через хук.
import { useRef } from "react";
import { useSize } from "@nivo/core";
import { ResponsiveLine } from "@nivo/line";
const ChartContainer = () => {
const containerRef = useRef(null);
const size = useSize(containerRef);
return (
<div ref={containerRef} style={{ width: "100%", height: 400 }}>
{size && (
<ResponsiveLine
data={data}
width={size.width}
height={size.height}
/>
)}
</div>
);
};
В этом подходе график полностью зависит от вычисленных размеров контейнера.
На первом цикле рендера useSize может возвращать
null, поскольку DOM ещё не измерен. Это требует условного
рендера компонента графика.
Типовая логика:
useSize получает ссылкуResizeObserverВнутренняя реализация обычно базируется на
ResizeObserver, который реагирует на любые изменения
геометрии элемента:
Это позволяет избегать ручных обработчиков
window.resize.
Несмотря на удобство, подход имеет ряд особенностей:
В ряде сценариев автоматическое измерение оказывается избыточным.
Тогда применяется ручное управление width и
height, полностью исключающее useSize.
<ResponsiveLine
data={data}
width={800}
height={400}
/>
Такой подход используется:
Ручное управление часто комбинируется с состоянием:
import { useState, useEffect } from "react";
import { ResponsiveLine } from "@nivo/line";
const Chart = () => {
const [size, setSize] = useState({ width: 600, height: 300 });
useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth * 0.8,
height: 400
});
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return (
<ResponsiveLine
data={data}
width={size.width}
height={size.height}
/>
);
};
Такой подход даёт полный контроль над логикой адаптации.
В продвинутых интерфейсах часто применяется гибридная схема:
useSize определяет базовый размер контейнераconst width = Math.min(size.width, 900);
const height = Math.max(size.height, 300);
Это позволяет избегать деградации визуализации при слишком малых или больших контейнерах.
Nivo предоставляет responsive-компоненты, которые внутри используют
измерение контейнера. Однако при необходимости тонкой настройки
useSize даёт более низкоуровневый контроль.
Разница подходов:
При использовании useSize в flex/grid layout возникают
нюансы:
Поэтому стабильное измерение требует корректной структуры DOM:
.parent {
display: flex;
height: 500px;
}
.child {
flex: 1;
}
ResizeObserver может вызывать частые обновления при анимациях или изменении layout. В сложных dashboards это приводит к лишним ререндерингам графиков.
Типовые меры:
При серверном рендеринге размеры DOM неизвестны. Это создаёт разрыв между серверным HTML и клиентским вычислением.
Стратегии решения:
const isClient = typeof window !== "undefined";
return isClient ? (
<Chart />
) : (
<div style={{ height: 300 }} />
);
На практике встречаются повторяющиеся проблемы:
0 в width/heightrefСтабильная работа Nivo-графиков достигается при соблюдении нескольких принципов:
В крупных приложениях useSize используется как слой
адаптации между layout-системой и графиками. Он выступает в роли
прослойки, которая превращает DOM-геометрию в численные параметры
визуализации.
Такой подход позволяет: