Resize Observer — это веб-API, которое позволяет отслеживать изменения размеров DOM-элементов. В контексте библиотеки Atomico оно интегрируется через реактивные хуки, обеспечивая эффективное управление компонентами при изменении их размеров.
В стандартном JavaScript ResizeObserver создаётся как
объект, которому передаётся функция обратного вызова:
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
console.log(entry.contentRect.width, entry.contentRect.height);
}
});
Метод observe привязывает наблюдатель к конкретному
элементу:
observer.observe(element);
Метод unobserve отключает наблюдение, а
disconnect полностью прекращает работу наблюдателя.
Atomico предлагает удобные хуки для интеграции
ResizeObserver в реактивные компоненты. Основной подход —
использование useResizeObserver, который возвращает текущие
размеры элемента и автоматически обновляет их при изменении.
import { c, useResizeObserver } from "atomico";
function myComponent() {
const [ref, rect] = useResizeObserver();
return (
<host shadowDom>
<div ref={ref} style={{ width: "100%", height: "200px", background: "lightblue" }}>
Ширина: {rect.width}, Высота: {rect.height}
</div>
</host>
);
}
customElements.define("my-component", c(myComponent));
Здесь ключевые моменты:
ref — ссылка на DOM-элемент, который нужно
наблюдать.rect — объект с актуальными размерами
{ width, height, top, left }.ResizeObserver отслеживает контентные
размеры элемента. В Atomico это можно расширять через
опции:
const [ref, rect] = useResizeObserver({
box: "border-box" // отслеживать размер с учётом границ и паддингов
});
Доступны следующие значения свойства box:
"content-box" — учитывает только контент без паддингов
и границ."border-box" — учитывает границы и паддинги,
соответствует CSS box-sizing: border-box."device-pixel-content-box" — учитывает физические
пиксели на устройстве, полезно для canvas и high-DPI.Resize Observer может вызывать большое количество обновлений при динамических изменениях DOM. В Atomico можно оптимизировать реактивные обновления:
import { useResizeObserver } from "atomico";
import { useState, useEffect } from "atomico";
function useThrottledResize(ref, delay = 100) {
const [rect, setRect] = useState({ width: 0, height: 0 });
useResizeObserver(ref, entry => {
clearTimeout(ref._timeout);
ref._timeout = setTimeout(() => {
setRect(entry.contentRect);
}, delay);
});
return rect;
}
requestAnimationFrame для плавного
обновления размеров без лишних ререндеров.Пример с адаптивной сеткой:
function gridItem() {
const [ref, rect] = useResizeObserver();
const columns = Math.floor(rect.width / 150);
return (
<host>
<div ref={ref} style={{ display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)` }}>
<div>Элемент 1</div>
<div>Элемент 2</div>
<div>Элемент 3</div>
</div>
</host>
);
}
useResizeObserver синхронизирован с жизненным циклом
компонента: при удалении элемента наблюдение прекращается
автоматически.querySelector.useState,
useEffect) для построения сложной логики на основе
изменения размеров.Atomico позволяет наблюдать сразу несколько элементов, используя
массив refs:
const refs = [useResizeObserver(), useResizeObserver()];
return (
<host>
<div ref={refs[0][0]}>Элемент A: {refs[0][1].width}</div>
<div ref={refs[1][0]}>Элемент B: {refs[1][1].width}</div>
</host>
);
Каждый ref сохраняет свой собственный объект
rect, полностью независимый и реактивный.
ResizeObserverAtomico упрощает следующие аспекты:
Atomico превращает работу с ResizeObserver из
низкоуровневого API в чистую реактивную декларацию,
сохраняя контроль над производительностью и упрощая интеграцию в сложные
компоненты.