Очистка ресурсов

Floating UI в JavaScript предоставляет гибкую систему позиционирования всплывающих элементов, таких как тултипы, модальные окна, дропдауны и поповеры. Для эффективного использования библиотеки крайне важно правильно управлять ресурсами и очисткой эффектов, чтобы избежать утечек памяти и некорректного поведения элементов на странице.


Автоматическое удаление обработчиков событий

Когда создается floating-элемент с помощью computePosition или хуков вроде useFloating, библиотека добавляет обработчики событий на окно и документ для отслеживания изменения размеров, скролла и положения целевого элемента.

Пример создания позиционируемого элемента:

import { computePosition, offset, flip, shift } from '@floating-ui/dom';

const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');

computePosition(reference, floating, {
  middleware: [offset(8), flip(), shift()],
}).then(({ x, y }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

После этого Floating UI регистрирует слушатели событий на скролл и ресайз. Если элемент будет удален из DOM без очистки, эти слушатели останутся, что приведет к утечкам памяти и ненужным вычислениям.


Функция cleanup и возвращаемые функции от autoUpdate

Для упрощения управления ресурсами библиотека предоставляет утилиту autoUpdate, которая автоматически обновляет положение floating-элемента при изменениях DOM.

Использование с очисткой ресурсов:

import { autoUpdate } from '@floating-ui/dom';

const cleanup = autoUpdate(reference, floating, () => {
  computePosition(reference, floating, {
    middleware: [offset(8), flip(), shift()],
  }).then(({ x, y }) => {
    Object.assign(floating.style, {
      left: `${x}px`,
      top: `${y}px`,
    });
  });
});

// Когда элемент больше не нужен
cleanup();
  • Возвращаемое значение autoUpdate — функция, вызываемая для удаления всех подписок и обработчиков.
  • Вызов cleanup() гарантирует полное освобождение ресурсов: слушатели событий удаляются, вычисления прекращаются.

Очистка при удалении из DOM

Если floating-элемент удаляется динамически, необходимо убедиться, что очистка вызывается до удаления элемента:

button.addEventListener('click', () => {
  floating.remove();
  cleanup(); // удаляет слушатели и прекращает автообновление
});

Пренебрежение этим правилом приводит к dangling listeners, которые будут продолжать работать с несуществующими элементами и вызывать ошибки в консоли.


Контроль middleware и их жизненного цикла

Middleware в Floating UI также могут создавать временные объекты, например, измерительные контейнеры или временные прокси для расчета размеров. Для некоторых middleware можно явно запускать методы очистки, особенно при использовании кастомных решений:

import { arrow } from '@floating-ui/dom';

const arrowMiddleware = arrow({ element: arrowEl });

// computePosition с middleware
const position = await computePosition(reference, floating, {
  middleware: [offset(8), flip(), shift(), arrowMiddleware],
});

// При удалении
if (arrowMiddleware.cleanup) {
  arrowMiddleware.cleanup();
}

Такой подход предотвращает накопление временных элементов в DOM и повышает производительность приложения.


Управление React-хуками Floating UI

В React используется пакет @floating-ui/react, где управление жизненным циклом элементов интегрировано через хуки useFloating и useInteractions.

Пример с автоматической очисткой:

import { useFloating } from '@floating-ui/react';
import { useEffect } from 'react';

function Tooltip({ referenceElement }) {
  const { x, y, reference, floating, update } = useFloating({
    placement: 'top',
  });

  useEffect(() => {
    reference(referenceElement);
    return () => {
      // cleanup вызывается автоматически при размонтировании
    };
  }, [referenceElement, reference]);

  return (
    <div ref={floating} style={{ position: 'absolute', left: x ?? 0, top: y ?? 0 }}>
      Подсказка
    </div>
  );
}
  • Возврат функции из useEffect гарантирует корректную очистку при размонтировании компонента.
  • Встроенные механизмы useFloating освобождают ресурсы, но при кастомной логике autoUpdate следует использовать явный cleanup.

Рекомендации по предотвращению утечек

  1. Всегда сохранять ссылку на функцию очистки при использовании autoUpdate.
  2. Вызывать cleanup при удалении элементов или размонтировании компонентов.
  3. Следить за middleware, особенно кастомными, которые создают временные элементы или подписки.
  4. Избегать вызова computePosition без контроля жизненного цикла, если элемент динамически создается и удаляется.
  5. Использовать React-хуки корректно, доверяя встроенной системе очистки, но комбинируя с ручной очисткой при кастомных эффектах.

Эти практики обеспечивают стабильность интерфейса, предотвращают утечки памяти и гарантируют корректное обновление позиции элементов в любом сценарии использования Floating UI.